들어가기 전에
CGI와 Servlet
동적 컨텐츠 처리의 역사
- 초기 웹 서버: HTTP프로토콜을 통해
정적
인 웹 페이지나 이미지만 제공
- CGI: 사용자 요청에 따라 상호작용할 수 있는
동적인 웹페이지 제공
을 위해 등장
CGI는 '웹 서버'와 '사용자 요청을 받아서 처리하는 외부 프로그램'을 연결하는 인터페이스입니다.
웹 서버가 클라이언트의 요청을 받으면 새로운 CGI프로세스를 생성하고, HTTP요청 정보를 해당 프로세스에 전달해 동적인 컨텐츠를 생성할 수 있도록 도와줍니다.
CGI는 각 요청마다 새로운 프로세스
를 생성해야하기 때문에 응답 시간이 오래 걸리며, 메모리를 공유하는 쓰레드에 비해 요청이 많아질수록 시스템에 부하가 커졌습니다.
- Servlet: 자바 진영에서 개발한
사용자의 요청에 따라 동적인 컨텐츠를 제공
하는 인터페이스입니다. 목적자체는 CGI와 크게 다르지 않다고 생각됩니다. 또한 서블릿을 통해 웹 요청과 응답을 간단한 메서드를 통해 효율적으로 처리할 수 있습니다.
- 서블릿의 특징
- 각 요청마다 프로세스가 아닌
쓰레드
를 생성하여 요청을 처리한다.
- Java언어로 구현되어있기 때문에 플랫폼에 독립적이다.
- JVM에 의해 관리되기 때문에 GC나 Memory leak에 대한 걱정을 덜 수 있다.
위 그림처럼 서블릿은 Web Container안에 load되어 있습니다. Web Container가 클라이언트 요청을 처리하는 과정은 다음과 같습니다.
- Step1. 사용자가 서블릿을 필요로하는 특정 URL에 해당 HTTP요청을 보낸다.
- Step2. 컨테이너(Web Container)는 요청 URL을 처리하기 위해 서블릿이 필요하다는 것을 확인한다.
- Step3. 컨테이너가 'HttpServletRequest'와 'HttpServletResponse'라는 객체를 생성한다.
- Step4. 컨테이너가 요청 URL에 매핑되는 서블릿을 찾고, 요청을 처리하기 위한 쓰레드를 생성(또는 할당(allocate))한 후, 앞서 만든 request와 response객체를 서블릿 쓰레드에 전달한다.
- Step5. 컨테이너는 서블릿의 service()메서드를 호출하고, 메서드 수행이 완료되면 컨테이너는 사용자에게 HTTP 응답을 반환한다.
-> url처리에 적합한 서블릿을 찾고, 해당 서블릿에 Request,Response객체를 주입하고, 서블릿의 service()메서드를 호출하는 역할을 수행합니다.
Web Server, Web Application Server, Web Container
-
Web Server: 클라이언트로부터 HTTP요청을 받고, HTML문서와 같은 정적인 컨텐츠를 반환하는 프로그램
-
WAS: Web Server와 달리 동적인 컨텐츠를 제공해줄 수 있습니다. 동적인 컨텐츠 제공은 WAS내의 Web Container가 담당합니다.
WAS는 쉽게 말해 정적인 컨텐츠를 반환하는 Web Server, 그리고 동적인 요청을 처리하는 Web Container로 구성되어 있다고 볼 수 있습니다.
그리고 Web Container는 서블릿과 상호작용하는 컴포넌트로 볼 수 있습니다.
-
Web Container(== Servlet Container): 웹 서버와 자바 서블릿 간의 상호작용을 담당하는 서블릿의 runtime environment입니다. (Servlet을 위해 존재하는 공간)
- 주요 기능
- 서블릿 생명주기 관리(load -> init -> service -> destroy)
- URL과 해당 URL을 처리할 서블릿 매핑
기타) 스프링 부트를 이용하면
- 스프링 부트가 내장 톰캣 서버를 생성해 줍니다.
톰캣은 자체적으로 서블릿 컨테이너 기능을 가지고 있기 때문에 서블릿을 생성합니다.
- HTTP요청이 들어왔을 때의 과정은 동일합니다. (response,request객체를 만들어 요청을 처리할 Servlet에 전달한 뒤 service메서드를 실행하고, 그 결과로 만들어진 response를 http에 담아 사용자에게 응답을 반환)
웹서버와 웹어플리케이션의 상호 보완관계
아파치 톰캣
- 서블릿 컨테이너를 포함하고 있는 웹 서버(Web Server + Servlet Container), Servlet을 활용한 동적 컨텐츠 응답이 가능하기 때문에 WAS로 불리기도 합니다.
- 톰캣 아키텍쳐
- 톰캣 서버의 요청 처리 흐름
- 클라이언트가 톰캣 서버의 80번 포트로 HTTP요청을 보냄
해당 포트의 Connector는 Engine으로 해당 요청을 전달함
Service는 Connector와 Engine을 연결해주는 컴포넌트
- Engine은 Connector로부터 요청을 받은 후 요청에 맞는 Host내 Context, 즉 어플리케이션에 요청을 전달함
- Context는 '/WEB-INF/web.xml'에 정의된 서블릿 매핑 정보를 참고해 요청에 맞는 Servlet을 찾고, 해당 Servlet에게 요청을 전달
- Servlet이 반환하는 응답은 Context -> Engine -> Connector를 통해 클라이언트에게 전달됨
리버스 프록시 서버
Apache HTTP Server나 Nginx와 같은 웹 서버를 톰캣과 함께 활용하면 다음과 같은 이점을 얻을 수 있습니다.
- Load Balancing: 톰캣 인스턴스를 여러개 띄울 때 Appache HTTP server를 앞단에 두어 부하분산 역할을 진행할 수 있습니다.
- Security: 클라이언트에서 WAS를 직접 접근하지 않기 때문에 서버 어디에 파일이 있고, 서비스가 몇번 포트로 제공되는지와 같은 정보를 클라이언트로부터 숨길 수 있습니다.
- High-availability: 여러 톰캣 인스턴스를 띄웠을 때, 하나가 죽으면 다른 인스턴스로 요청을 처리할 수 있습니다.
- Caching: 클라이언트가 자주 찾는 리소스를 웹서버에 캐싱하여 WAS까지 가지 않고 곧바로 응답을 줄 수 있습니다.
- Cengralized authentication/authorization: 인증 관리를 한 곳에서 수행할 수 있습니다.
Apache HTTP Server
- 아파치 재단에서 1995년 공개한 오픈소스 웹 서버입니다.
- 클라이언트로부터 요청을 받으면 새로운
프로세스
를 생성하고, 해당 프로세스를 통해 요청을 읽고 응답하는 방식입니다.. 프로세스 기반 아키텍쳐
- 요청마다 프로세스를 생성하는 방식이 비효율적이었기 때문에 요청 처리할 프로세스들을 미리 준비해놓는
prefork
방식을 도입했습니다.
- 웹 사용량이 증가하자 Apache HTTP Server는 문제가 발생했습니다.
- 클라이언트 요청마다 프로세스를 할당하는 방식은 동시에 처리해야하는 클라이언트 요청이 증가함에 따라 메모리가 부족해 프로세스를 할당하지 못하는 어려움을 겪었습니다.
- 이를
C10K Problem
이라고 합니다.
Nginx
이벤트 기반 아키텍쳐
- 각각의 worker process는 수천개의 HTTP커넥션을 동시에 처리할 수 있습니다.
worker process는 클라이언트로부터 HTTP 커넥션 요청을 받을 때 생성되는 event를 기다리다가, 이벤트가 발생되면 다른 이벤트를 블락하지 않고 비동기
적으로 이벤트를 처리합니다.
비교
- Apache는 Nginx에 비해 설정이 간편하고 '.htaccess'파일에 접근할 수 있기 때문에 서버 설정을 보다 세세하게 할 수 있으며, 모듈을 통해 요청 처리 방식을 선택할 수 있습니다.
- Nginx는 이벤트 기반의 비동기적인 작업 방식을 통해 동시 요청을 효율적으로 처리할 수 있습니다.
결론
- Servlet: 자바 진영에서 개발한 사용자의 요청에 따라 동적인 컨텐츠를 제공하는 인터페이스
- Tomcat: 서블릿 컨테이너를 포함하고 있는 WAS
- Apache: 프로세스 기반 아키텍처의 웹 서버
- Nginx: 이벤트 기반 아키텍처의 웹 서버