웹 서버는 HTTP를 통해 웹클라이언트가 요청한 데이트를 제공해주는 프로그램이다.
개발자는 웹서버 프로그램으로 Apache나 Nginx같은 프로그램을 이용하게된다.
Apache
아파치 HTTP 서버는 아파치 소프트웨어 재단에서 관리하는 무료 HTTP 웹서버 소프트웨어다.
리눅스 등 유닉스 계열 뿐만 아니라 마이크로소프트 윈도우에서도 무료로 운용할 수 있다.
프로그램의 이름은 httpd로 기본적인 작동 방법은 사용자의 HTTP 요청이 올 때마다 프로세스나 스레드를 새로만든다.
따라서 사용자 동시 접속이 늘어날 수록 프로세스마다 메모리를 따로 따로 할당하기 때문에 메모리 낭비가 심하고 CPU가 여러 프로세스를 고속으로 번갈아 실행해야 하므로 CPU 부하가 높아지는 문제가 있다.
뿐만 아니라 아무리 서버의 하드웨어 성능이 좋다고 하더라도 동시에 연결된 커넥션이 1만 개가 넘어가면 서버는 더 이상 커넥션을 형성하지 못하는 일명 C10K 문제가 발생하게 된다.
아파치의 구동 방식으론 두가지가 있다.
HTTP 연결 요청이 올 때마다 프로세스를 매번 복제하여 프로세스에서 싱글 스레드로 해당 HTTP 요청을 처리하는 즉 사용자 요청수 = 프로세스 수가되는 Prefork MPM(multi Processing Module) 방식과
한개의 프로세스가 여러 스레드를 생성해 해당 HTTP 요청을 처리하므로 Prefork 방식보다 메모리 소모가 적지만 CPU 스케줄링을 위한 처리시간과 문맥 전환 비용이 발생하고 스레드를 분배하기 위해 사용되는 CPU 스케줄링에 대한 연산 작업과 쓰레드간의 전환을 위해 전환하기 직전의 쓰레드를 나중에 복귀시킬 때를 대비하여 상태를 저장해두기 위한 CPU 연산 작업으로 인해 스레드가 많아질 수록 성능 저하가 발생하는 Worker MPM 방식이 있다.
Nginx
Nginx는 Apache의 C10K 문제를 해결하고자 등장했다.
Nginx는 요청에 응답하기 위해 비동기 이벤트 기반의 구조를 가지고 이것은 아파치 HTTP서버의 스레드/프로세스 기반 구조를 가지는 것과는 대조적이다.
비동기 이벤트란 HTTP 요청이 수 천개여도 정해진 수의 프로세스가 이 요청들을 이벤트로 등록하고 비동기 방식으로 대기시켜 완료되는 요청부터 응당해주는 것을 말한다.
Nginx는 1개의 master process와 3종류의 자식 프로세스로 구성되어 있다.
master process는 특권명령을 수행하고 싱글 스레드로 구성된 다수의 Worker process 관리를 한다.
- listen socket에 port를 바인딩
- Nginx 설정 읽기
- 3가지 타입의 자식 프로세스를 생성하고 관리
child process(자식 프로세스)는 총 3가지로 Nginx 시작시 실행되며 디스크 기반 캐시를 메모리에 불러오고 종료하고 보수적으로 스케줄링 되므로 리소스 요구사항은 낮은 cache loader와
주기적으로 실행되며 디스크 캐시를 설정된 사이즈로 유지하기 위해 캐시엔트리를 정리하는 cache manager,
listen 소켓을 배정받고 listen 소켓으로부터 클라이언트의 요청이 들어오면 커넥션을 형성하여 처리하고 초당 수천개의 모든 http 요청을 한 프로세스에서 처리하고 응답하며 문맥 전환을 줄이기 위해 non-blocking 방식으로 동작되고 cpu 1개당 1개의 프로세스를 생성하도록 설정하는게 권장되는 worker process가 있다.
Nginx에서는 커넥션 생성 및 커넥션 제거, 그리고 새로운 요청을 처리하는 것을 이벤트라고 부른다.
이 이벤트 들은 OS커널이 큐 형식으로 worker process에게 전달해주고, 이벤트가 큐에 담긴 상태에서 worker process가 처리할 때까지 비동기 방식으로 대기한다.
그리고 worker process는 하나의 스레드로 이벤트를 꺼내서 처리해 나간다.
이렇게 되면 worker process가 쉴틈없이 일하기 때문에 아파치 서버에서 요청이 없다면 방치되던 프로세스보다 서버자원을 더 효율적으로 쓸 수 있게 되는 것이다.
하지만 역시 문제점이 없지는 않은데 이벤트들 중 하나가 시간이 오래 걸리는 작업이면 그 뒤에 있는 이벤트의 요청을 처리하는데 걸리는 시간이 길어져 블로킹이된다.
다행히 이 문제에 대한 해결방법은 있다.
시간이 오래걸리는 작업은 따로 수행하는 스레드 풀을 만들어놓고 워커프레스는 시간이 오레걸릴 이벤트는 스테드 풀에 위임하고 다른 이벤트를 처리하러 가면된다.