본문 바로가기
Spring&SpringBoot

서버 구조 바로 알기 - WAS? Tomcat? Servlet Conainer???? (feat. Jar vs War)

by 민휘 2023. 5. 14.

 

스프링 부트의 패키징 방식의 차이점!

  • Jar : 단독으로 실행 가능한 자바 프로그램 패키지 형식으로, 애플리케이션 코드와 라이브러리 코드가 모두 포함됨. Jar로 패키징한 스프링부트 애플리케이션은 내장 서버를 포함하므로 JVM에서 바로 실행 가능하다.
  • War : 웹 애플리케이션을 패키징하는 형식으로, 웹 애플리케이션에 필요한 파일들을 하나의 파일로 압축. War 파일은 톰캣과 같은 WAS에 배포되어 실행되며, 서블릿 컨테이너에서 실행한다.

…을 알아보다가 WAS와 웹 서버, 서블릿 컨테이너가 갑자기 헷갈려서 개념을 다시 정리해보았다.

 

 

Web Server!

 

웹 서버는 클라이언트로부터 요청을 받고 응답을 하는 소프트웨어를 말한다. (하드웨어의 의미로 본다면 웹 서버 소프트웨어가 동작하는 컴퓨터를 말한다) 클라이언트의 요청이 단순한 정적 컨텐츠를 요구하는 경우 별도의 로직 없이 컨텐츠를 응답한다. 대표적으로 Apache, Nginx가 있다.

 

웹 서버는 주로 정적 컨텐츠 제공에 특화되어있지만, 간단한 로직을 가진 동적 컨텐츠 처리 역시 웹 서버에서 처리가 가능하다. 아파치와 PHP, MySQL을 연동해서 동적인 PHP 웹 사이트를 제공하는 APM이 있다.

 

하지만 아주 복잡하고 방대한 로직을 필요로 하는 경우, 이를 전문적으로 담당하는 서버를 따로 두고 웹 서버는 클라이언트의 요청을 전문 서버에 토스하는 역할을 수행한다. 이 전문 서버를 바로 WAS(Web Application Server)라고 부른다.

 

 

WAS?

 

WAS는 DB 조회나 외부 시스템 연동 등 복잡한 로직을 요구하는 동적 컨텐츠 제공에 특화된 애플리케이션 서버인 동시에, 클라이언트의 요청을 받고 응답할 수 있는 웹 서버이기도 하다. 예를 들어 Tomcat, JBoss, Jeus 등이 있다. 잠깐, 이게 무슨 소리인가? WAS는 웹 서버가 동적 컨텐츠를 처리할 수 없어서 나온 것이 아닌가?

 

응 아니야

사실 웹 서버와 WAS는 그 시작점이 다르다. 웹 서버는 HTTP 프로토콜 규약을 사용하는 서버(TCP 연결 수립 및 소켓 생성)였고, 앱 서버(WAS)는 폐쇄적인 사용자 그룹을 위해 폐쇄적인 프로토콜을 사용하는 서버였다. 웹 초기에는 정적 컨텐츠를 제공하는 것으로도 사용자들의 요구사항을 만족시켰으므로 웹 서버만으로 운영이 가능했다. 시간이 지나 웹 서비스의 인기가 많아지면서 애플리케이션 로직도 돌리고 싶고 DB에 데이터도 저장하고 싶어졌다. 하지만 웹 서버는 복잡한 동적 컨텐츠를 처리하는 기능을 처리할 수 없었다. 그래서 WAS에 웹 서버를 도입해 HTTP 프로토콜을 사용해 더 복잡한 작업을 할 수 있는 서버를 만든 것이다. 실제 WAS로 사용하는 제품인 Apache Tomcat을 뜯어보면 HTTP 요청을 받고 응답하는 웹 서버와 애플리케이션 로직을 실행할 수 있는 Web Container로 구성된다.

 

자세한 내용이 궁금하다면 아래 링크 참고!

[ Eassy - Technology, IT, Web ] Web Server와 Web Application 또는 Web Application Server(WAS)란 무엇인가?

 

[ Eassy - Technology, IT, Web ] Web Server와 Web Application 또는 Web Application Server(WAS)란 무엇인가?

 

nitro04.blogspot.com

 

결국 WAS 안에서 동적 컨텐츠를 제공하는 컴포넌트를 Servlet이라고 부르고, 클라이언트의 요청을 받아 적절한 Servlet으로 라우팅하는 컴포넌트를 Servlet Container라고 부른다. 그러니 웹 서버의 역할을 WAS 안에서는 서블릿 컨테이너가 수행하고 있다고 보면 된다.

WAS가 동적 컨텐츠 처리에 특화됐다고 해서 정적 컨텐츠를 제공하지 못하는 것은 아니다. 과거엔 톰캣의 정적 컨텐츠 서빙 성능이 그리 좋지 않았다고 하지만, 이젠 해결되어서 성능 상의 유의미한 차이는 없다. 그래서 WAS만 두어도 웹 애플리케이션을 띄워 사용자 요청을 받고 처리를 하고 응답하는 작업은 충분히 수행 가능하다.

 

그렇다면 왜!! 왜 톰캣 같은 WAS는 웹 서버 기능을 하는 서블릿 컨테이너를 내부적으로 가지고 있는데, Nginx 같은 Web Server를 추가적으로 두는 아키텍처를 선택하는 것일까?

 

 

Web Service Architecture

 

웹 서버와 WAS이 수행하는 역할에 겹치는 부분도 있지만, 각자 특화된 부분이 있다. 웹 서버는 요청을 받아 정적인 컨텐츠를 제공하고, WAS는 애플리케이션 로직을 처리해 동적인 컨텐츠를 제공한다. 하지만 이것만이 아니다. 웹 서버의 가장 기본적인 기능은 요청에 대한 응답이지만, 운영과 보안 측면에서 여러 기능을 제공한다.

 

  • 리버스 프록시 : 클라이언트가 실제 컨텐츠를 제공하는 서버 대신 요청을 받아서 컨텐츠 서버의 내부 구조를 감출 수 있다. 파일이 어느 폴더에 있는지, 서비스가 몇번 포트에서 동작하는지 감춘다.
  • 로드 밸런싱 : 트래픽이 몰릴 때 여러개의 WAS에 요청을 분산하는 작업을 말한다. WAS를 여러대 두면 지속적인 배포와 운영이 가능하고, 처리 성능이 더 좋아지기도 한다.
  • 캐싱 : 웹서버가 reverse proxy로써 제공한다. 클라이언트가 서버에 자주 요청하는 컨텐츠를 미리 캐싱해두어 WAS에 요청을 보내지 않고 처리하는 것을 말한다.
  • 헬스 체크 등 서비스의 안정성 확인

 

웹 서버는 정적 컨텐츠나 간단한 로직만 처리할 수 있는 바보인 줄 알았으나, 보안이나 안정적인 운영 기능을 수행할 수 있는 것이었다! 그래서 웹 서버와 WAS가 특별히 잘하는 부분을 골라서 아키텍처를 구성하면 이렇게 된다.

 

클라이언트의 요청을 웹 서버가 받아서 보안이나 로드 밸런싱, 프록시, 캐싱 등의 기능을 수행하고, 정적 컨텐츠나 간단한 처리가 필요하다면 본인이 수행한다. 복잡한 동적인 처리가 필요하다면 WAS의 Servlet Container로 요청을 넘긴다. 서블릿 컨테이너는 받은 클라이언트의 HTTP 요청 정보를 보고 처리를 해줄 적절한 서블릿을 찾아 라우팅한다. 서블릿이 데이터베이스나 외부 시스템과의 통신 등등 복잡한 비즈니스 로직을 만들고 나면 HTTP 응답을 만들고, 이 응답이 다시 서블릿 컨테이너와 웹 서버를 거쳐 클라이언트에게 가는 것이다.

휴 의문 해소~

 

 

그래서 결국 JAR와 WAR의 차이는?

 

처음 봤던 JAR와 WAR의 차이를 다시 살펴보자.

 

  • Jar : 단독으로 실행 가능한 자바 프로그램 패키지 형식으로, 애플리케이션 코드와 라이브러리 코드가 모두 포함됨. Jar로 패키징한 스프링부트 애플리케이션은 내장 서버를 포함하므로 JVM에서 바로 실행 가능하다.
  • War : 웹 애플리케이션을 패키징하는 형식으로, 웹 애플리케이션에 필요한 파일들을 하나의 파일로 압축. War 파일은 톰캣과 같은 WAS에 배포되어 실행되며, 서블릿 컨테이너에서 실행한다.

 

WAR 파일은 우리가 개발한 동적 처리를 가능하게 하는 애플리케이션을 패키징해서, WAS의 서블릿 컨테이너 안에서 실행되도록 배포된다. 이제 클라이언트 요청이 들어오면 서블릿 컨테이너가 잡아서 새로운 스레드를 생성하고, 스레드가 이 요청을 처리하는데 필요한 서블릿 객체를 생성하여 서블릿의 servlet() 메소드를 호출해 요청을 처리한다. 서블릿 객체는 우리가 열심히 개발한 애플리케이션 코드를 수행한다.

 

그런데 생각해보면 스프링이나 스프링부트를 사용해서 개발할 때 Servlet 객체를 생성하는 코드는 작성한 적이 거의 없다. 그 이유는 스프링이 서블릿과 관련된 코드 작성을 추상화해서 개발자가 비즈니스 로직 작성에만 집중할 수 있도록 도와주기 때문이다. 컨트롤러 메소드를 작성할 때, 매개변수 오브젝트로 HTTP 요청의 Path Variable이나 HTTP Request Body 값이 들어오는 것을 보고 신기했던 적이 있는가? 이러한 바인딩 작업은 스프링이 제공하는 HandlerMethodArgumentResolver을 통해서 이루어진다.

 

JAR 파일은 스프링이 독립 실행이 가능한 애플리케이션으로 만들어주는 스프링부트에서 많이 사용하는 애플리케이션 패키징 방식이다. 앞에서 보았듯이 WAR은 애플리케이션 패키징을 해두고, 서블릿 컨테이너 만들어서 설정 뚝딱 뚝딱 하고 WAR을 배포한다. 즉 애플리케이션 개발 따로, WAS 설정 따로 해주어야한다는 소리다. 문제는 개발자는 애플리케이션 개발만 해도 죽겠는데 WAS 세팅이 굉장히 어렵고 일회용인데다, WAR 패키징할 때 구조에 맞게 이쁘게 세팅까지 해주어야한다는 점이다.

 

독립 실행형 애플리케이션은 위의 방식과 달리 애플리케이션이 WAS를 내장하고 있다. 그래서 힘들게 세팅할 필요 없이 애플리케이션만 실행하면 WAS가 같이 실행된다. 이러한 독립 실행형 애플리케이션을 스프링으로 지원하기 위해 나온 프로젝트가 스프링 부트이다. (이것 말고 자동 구성도 있다)

 

스프링부트는 그냥 애플리케이션이다. 다만 내장 서버를 오브젝트로 가지고 있을 뿐이다. 그래서 평범한 자바 애플리케이션을 패키징하듯이 JAR로 패키징이 가능하고, 이것을 JVM에 바로 올렸을 때 실행이 가능한 것이다.

내장 톰캣을 가진 JAR로 배포하는 것은 여러모로 개발자에게 도움이 된다. 이것은 아파치 톰캣 설치와 설정 한번만 해보면 스프링부트에게 무한한 감사함을 느낄 수 있다 ^^ 그리고 JAR 파일만 있으면 JRE로 어느 환경에서든 실행이 가능하다. 덕분에 JAR 파일은 도커 이미지로 만들어 배포하는 경우에 유리하다. JDK 이미지를 다운받고 jar 파일만 추가하면 된다! 따라서 스프링부트로 만든 JAR는 MSA를 구성할 때 적합하다는 장점이 있어 많이 사용된다.

 

 

이상으로 길고 길었던 서버 구조의 혼란을 마무리한다.

 

 

 

참고 자료

'Spring&SpringBoot' 카테고리의 다른 글

Containerless Spring Boot  (1) 2023.05.12