본문 바로가기

TIL

TIL) Webserver vs WAS, NGNIX vs Apache

[웹서버]

웹서버는 정적인 자원만을 처리할 수 있다. (html, css) (Apache Http Server)

 

[CGI]

동적인 자원 즉 요청된 데이터로 어떤 프로그래밍 작업을 한 후 응답을 주는 니즈가 생김.

그래서 생긴게 CGI (Common Gateway Interface). (인터페이스다.)

이는 웹서버와 CGI 구현체 사이의 인터페이스 즉 규약이다.

웹서버에서 에서 동적인 응답을 받고, 자신이 처리하지 못해 CGI 구현체에게 줄 때의 규약이다.

 

[CGI 단점]

하지만 이 CGI 는 웹서버 -> CGI 구현체로 요청을 줄 때 한 요청당 프로세스를 만든다.

그리고, 한 프로세스마다 하나의 CGI 구현체를 사용한다.

따라서 한 요청에는 프로세스 한개, CGI 구현체 한개를 만들어 사용해야 한다.

  • 프로세스 : 메모리에 적재된 하나의 프로그램 인스턴스. 즉 프로그램 하나당 메모리 할당을 따로 받는다.
  • 스레드 : 한 프로세스 내의 작업 단위. 스레드들은 프로세스의 자원을 공유하기 때문에 생성하는 비용이 프로세스보다 적다. (따로 OS 에게 할당받지 않아도 됨.)

[CGI 단점을 해결한 Servlet]

CGI 의 단점 두가지를 고쳐보자.

  • 프로세스 -> 스레드
  • 하나의 프로세스당 하나의 CGI -> 여러 스레드당 하나의 서블릿 구현체 구현체

로 만든게 Servlet 구현체이다.

그리고 Servlet 이란건 웹서버와 서블릿 구현체 사이의 규약을 정해놓은 인터페이스 프로그램이다.

 

이 서블릿은 자바로 짜여진 인터페이스이다. (그래서 was 는 자바가 많다)

우리는 원하는 방식대로 이 서블릿의 구현체를 만들어서,

계산을 한다든지, DB 에서 값을 꺼내온다든지 등등의 동적인 처리 코드를 짠다.

 

[WAS - Servlet Container]

서블릿이란건 단지 코드일 뿐이다.

이를 실행시켜주는것이 WAS 이다.

  • WAS = 서블릿 컨테이너 : 서블릿 구현체들이 만들어져 저장되는 곳이다.
  • WAS 는 webserver 에게 동적 처리 요청을 받는다.
  • WAS 는 요청당 스레드를 만들거나 스레드풀에서 받아 할당한다. 
  • 이 스레드는 이제 서블릿이 실행될 장소가 마련된 것이다.
  • WAS 는 스레드에서 각 서블릿들을 실행한다.

 

 

[요청 ~ 서블릿 컨테이너 ~ 처리 흐름]

  1. 클라이언트에서 Http Request 전송.
  2. 동적 요청이라면, WebServer 가 WAS 에게 요청 넘김.
  3. WAS 는Servlet 실행 준비 및 실행. (아래는 WAS 가 하는 일임)
    1. HttpServletRequest, HttpServletResponse 객체 생성.
    2. 배포 서술자(Web.xml), 또는 에너테이션을 통해 요청 URL 과 맵핑된 서블릿 선정.
    3. 스레드를 생성하거나 스레드풀에서 스레드 잡음.
    4. 스레드에서 서블릿 실행.
      1. 새로 생성하는 서블릿이라면 init() - service() 순으로 호출.
      2. 보통 서블릿(인터페이스)은 객체를 한번 만든 후, 같은 요청들에 대해서는 재사용한다. (init() 호출 없이 service() 만.)
      3. 이 메서드 생성에서 HttpServletRequest, HttpServletResponse 객체를 인자로 넘겨줌.
      4. service() 메서드 에서는 요청에 맞게 doGet(), doPost(), doPut() 등의 메서드를 실행.
  4.  서블릿 동작과정에서 응답은 HttpServletResponse 에 기록해서 client 에게 반환.
  5. 종료 과정.
    1. 스레드 : 한 요청이 종료되면, 스레드는 반납되어 스레드풀로 다시 보내진다.
    2. HttpServletRequest, HttpServletResponse : 역할이 끝나고 가비지 컬렉션의 대상이 된다.
    3. Servlet : 서블릿은 한 서블릿의 여러 요청 스레드들이 모두 종료되거나, timeout 이 되면 destroy() 메서드를 호출해서 종료시킨다. 이 destroy() 메서드를 실행시키는 것은 WAS 이다.

 

이 과정에서 서블릿 구현체의 객체가 있어야 WAS 가 메서드를 실행시킬 수 있다.

서블릿 객체는 맵핑된 URL 에 대한 첫 요청시 생성되어, 여러 비동기적인 해당 URL 요청의 스레드들에 대해 재사용된다.

또, loadOnStartUp 속성을 이용하면 첫 요청시가 아니라, 컨테이너가 띄워질 때 미리 해당 서블릿 객체를 생성할 수 있다.

 

 

 

 

https://webfirewood.tistory.com/41?category=698497 

 

서블릿(servlet) 생명주기(lifecycle)

우선 지난 시간에 배웠던 Servlet의 동작 순서를 다시한 번 복습 하겠습니다. 여기서 컨테이너는 매핑된 서블릿을 찾아서 service() 메소드를 호출한다고 했습니다. 그런데 어떤 클래스의 메소드를

webfirewood.tistory.com

 

 

 

[Spring 의 DispatcherServlet]

원래 서블릿은 URL 과 1:1 이다. 서블릿과 URL 맵핑정보는 배포서술자(Web.xml) 에 작성한다.

물론 한 URL 과 여러 비동기적 요청에 의해 생성된 스레드는 1:N 이다.

결국 [요청-URL-스레드-서블릿 = N:1:N:1] 이다.

 

요청마다 Setvlet 이 다르다면, 여러 Servlet 이 필요하다.

하지만 Spring 에서는 dispatcherServelt 이라는 특별한 Servlet 구현체를 사용한다.

이 서블릿은 모든 요청을 받는다.

그래서 Spring 에서는 Url 마다 서블릿을 만들 필요 없이, 서블릿 1개로 관리가 가능하다.

스프링 프로젝트를 만들어서 Web.xml 을 보면, dispatcherServelt 하나만 서블릿 등록이 되어있는걸 볼 수 있다.

 

스프링에서는 하나의 dispatcherServlet 이 뜨고, 이 안에서 메모리를 공유하는 여러 스레드들이 요청으로 들어오게 된다.

 

스프링은 dispatcherServlet 으로 요청을 받은 후, requestHandler 과 requestAdatper 등을 사용해서 컨트롤러와 연결시키는데, 이는 지금 다루지는 않겠다.

 

참고 : 테코톡

https://www.youtube.com/watch?v=2pBsXI01J6M 

 

 

 


 

2. Nginx vs Apache

[구조]

Apache

  • 아파치 웹서버는 다중처리 모듈(MPM. Multi-Processing Module) 방식을 사용하며, 대표적으로 2가지 종류가 있다.
  • prefork : 요청이 들어오면 자식 프로세스를 관리하는 부모 프로세스가 자식 프로세스에 요청을 할당한다. 자식 프로세스는 하나의 스레드를 가지고 있다. 따라서 한 요청에 하나의 프로세스 전체를 쓰기에, 높은 성능을 요하는 요청에 유리하다.
  • worker : prefork 방식과 비슷하지만, 자식 프로세스에 프로세스 자원을 공유하는 여러 스레드가 있다. 한 요청당 하나의 스레드를 차지한다. prefork 에 비해 자원을 적게 차지하고 프로세스를 띄우는 과정이 적기 때문에 시작 시간이 빠르다.

 

프로세스든 스레드든 정해진 한계만큼의 요청을 받을 수 있다. 그 이상의 요청은 받지를 못한다.

 

 

Nginx

  • 엔진엑스는 Event-Driven 방식이다. 요청이 들어오면 아래 3단계에 의해 처리된다.
    1. Event Queue 에 요청이 쌓인다.
    2. Thread Pool 에는 작업을 처리할 스레드들이 모인다.
    3. Event Loop 에서는 EventQueue 에 들어온 요청을 Thread Pool 에서 작업가능한 Thread 에 비동기적으로 처리시킨다.
  • 이런 이벤트 발행 방식은 여타 이벤트 방식처럼 관심사를 분리하여 느슨한 결합을 유지시킬 수 있다.
  • 또, 아파치와 달리 nginx 의 자원과 상관없이 요청을 받을 수 있다. (큐에 쌓아놓으면 되니까.)

그리고 Nginx 는 프로세스가 아래와 같이 3가지가 있다.

  • Master Process : config 파일을 읽고 검증, worker 프로세스를 관리
  • Worker Process : 실제로 동작을 수행하는 프로세스. 위의 Event-Driven 방식으로 요청을 받아 처리한다.
    • 다수의 워커 프로세스가 Nginx 설정에 의해 (CPU 코어 수에 맞게 설정되는게 디폴트) 생성된 후, 클라이언트의 요청이 늘어나는것에 상관없이 고정적으로 처리된다.
  • Cache Process : 캐시 로더, 캐시 매니저

 

요청이 비동기적으로 처리되기 때문에, 동기적으로 처리할 때 주로 나타나는 컨텍스트 스위칭이 적다.

 

 

 

이 두 동작방식으로 미뤄봤을때,

Nginx 는 아래의 상황에서 유리하다 할 수 있다.

  • 가벼운 작업. DB, Network, I/O 등의 작업들. 
  • 많은 요청이 들어와도 큐에 쌓아놓고 순차적으로 처리할 수 있고, 프로세스 기반이 아닌 스레드 기반이므로 생성시간이 짧아 빠르게 처리할 수 있다. 또, 한 프로세스의 여러 스레드들은 그 프로세스의 공유자원을 사용할 ㅜㅅ 있다.

 

=> Reverse Proxy 로 많은 곳에서 사용된다.

 

https://velog.io/@moonyoung/Nginx%EC%99%80-Apache

 

Nginx와 Apache

Ngingx와 Apache 비교하기

velog.io