(이 문서는 Nginx 중심으로 작성되었으며, Apache는 Nginx의 등장 배경을 위해 언급된 수준입니다.)
Nginx
- 클라이언트와의 connection을 유지는 event-driven 방식에 기반한다.
- Nginx 내 process에는 master process가 있고, config에 따라 worker process를 생성한다.
각 worker process는 만들어질 때, 지정된 listen socket으로 배정 받는다.
socket에 새로운 클라이언트의 요청이 들어오면,
connection을 형성하고 요청을 처리하며 keep-alive에 의해 유지되곤 한다.
- 각 worker process는 하나의 connection만 담당하는 것이 아니라
해당 connection에 아무런 요청이 없으면 그 동안에,
다른 새로운 혹은 이미 만들어진 connection의 요청도 처리한다.
- Nginx에서는 connection의 형성/제거 및 요청을 처리하는 것을 아울러 event라고 한다.
- OS kernel이 event를 queue에 담아 놓고, worker process에 전달한다.
event는 queue에서 비동기 방식으로 대기하며 (event loop),
worker process에서는 single thread로 event를 처리한다.
- worker process가 쉬지 않고 일할 수 있는 구조임에 따라 메모리 낭비가 없다.
- 만약 worker process에 할당된 event가 disk i/o 등 시간이 오래 걸리는 작업이라면,
해당 요청을 처리하는 동안 다음 event는 꽤 오래 blocking 될 수 있다.
Nginx에서는 이런 상황을 방지하기 위해 thread pool에서 수행하도록 한다.
worker process는 thread pool에 위임하고 다음 event를 수행한다.
이를 미루어, Nginx의 event-driven 방식을 non-blocking 이라고 한다.
- worker process는 보통 CPU의 Core 수만큼 생성한다.
이를 통해 CPU 입장에서 context switching을 최소화한다.
- config 파일 내용을 동적으로 바꿀 수 있다.
- 개발자가 config을 변경하고 적용하면, 그에 따른 새로운 worker process가 만들어진다.
기존의 worker process는 더 이상 connection을 형성하지 않도록 한다.
시간이 지나 기존 worker process가 담당하던 event 처리가 끝나면, 그 process를 종료한다.
- Load Balancing을 하고자 할 때 효과적이다.
Nginx를 종료하지 않아도 되므로, connection을 계속 유지할 수 있다.
- 초기의 Apache를 보완하고자 등장하였다.
- 동시 connection 수 증가
- 동시 connection 수: 어떤 임의의 시점에 대해서,
요청을 처리하기 위해 얼마나 많은 클라이언트와 connection을 유지하고 있는지.
- 하나의 클라이언트는 하나의 connection을 통해 여러 요청을 보낼 수 있다.
connection 유지는 HTTP의 kepp-alive를 통해 가능하며
이는 매 요청 마다 발생할 수 있는 3-way handshake를 생략해준다.
- connection 관리에 따른 메모리 효율성 및 초당 요청 처리 수 증가
- 초당 요청 처리 수: 서버가 얼마나 빨리 요청을 처리 할 수 있는지.
Apache
- multi process 방식(MPM)을 기반으로 클라이언트와 connection을 유지한다.
- MPM-prefork: 클라이언트마다 하나의 process를 할당한다.
- MPM-worker: 한 process 내에서 클라이언트마다 하나의 thread를 할당한다.
- 이러한 방식으로는 memory를 계속 점유하기 때문에 resource가 부족하게 되고,
과거엔 일명 C10K(connection 1만 개) 문제 등, connection 생성에 한계가 있다.
- 호환성(windows) 및 확장성(module 제공), MPM 방식에 따른 안정성 면에서 Nginx보다 우세하다.