Apache와 NginX는 현재까지 폭 넓게 사용되는 웹 서버이다. 이 두 가지 서버는 현재 전체 웹서비스의 절반 이상을 차지할 정도로 점유율이 높다. 그렇다면 이 두 서버의 장단점과 차이점은 무엇일까?
아파치 HTTP 서버(Apache HTTP Server)
는 아파치 소프트웨어 재단에서 관리하는 무료 HTTP 웹 서버 소프트웨어이다. 리눅스 등 유닉스 계열 뿐 아니라 마이크로소프트 윈도우에서도 무료로 운용할 수 있다.
아파치 서버는 요청
이 들어올 때마다 커넥션을 형성하기 위해 프로세스를 생성한다. 이는 유닉스 계열 OS가 네트워크 커넥션을 형성하는 형태를 가져온 것이다. 하지만, 프로세스를 만드는 방식은 시간이 오래 걸리므로 요청이 들어오기 전에 프로세스를 만들어 놓는 prefork
방식을 사용한다. 따라서 새로운 요청이 들어오면 prefork로 미리 만들어 놓은 프로세스를 사용하였다. 만들어 놓은 프로세스가 모두 소진되었다면 새로운 프로세스를 만들었다.
이러한 구조의 아파치 서버는 다양한 모듈을 만들 수 있었고 확장성이 높아졌다. 따라서 개발하기가 쉬워졌다. 그리고 확장성이 높으므로 request를 받고 response 보내는 과정을 하나의 서버에서 해결할 수 있었다.
하지만 이러한 Apache는 컴퓨터가 보급됨에 따라 서버에 동시에 연결된 커넥션이 많아 졌을 때 더 이상 커넥션을 생성하지 못하는 문제점이 발생한다. 이를 C10K
문제라고 한다.
❓ C10K [Connection 10,000 Problem]
동시에 연결되어 있는 커넥션 수가 10,000 단위를 넘어가면 더 이상 커넥션을 형성하지 못하는 문제점이 발생
커넥션이 생성될 때마다 프로세스가 생성되므로 커넥션 수가 많아지면 메모리 부족으로 이어진다. 따라서 무거운 프로그램이 된다. 그리고 CPU 부하가 많아진다. (Context Switching이 많이 하게 되므로)
이러한 아파치의 구조 때문에 많은 동시 커넥션을 감당하기에는 적합하지 않았다. 이러한 문제를 개선하기 위해 MPMs(Multi Processing Modules)
로 아파치 서버를 어떤 방식으로 운영할 지 선택할 수 있다.
위에서 아파치 서버의 문제점이 대두되면서 NginX가 개발되었다. NginX는 아파치 서버를 대체하려고 만든 것이 아닌, 아파치와 병행해서 사용하려고 개발된 것이었다.
아파치 서버 앞에
NginX를 배치해서 동시 커넥션을 NginX가 받도록 하였다. NginX는 웹서버
이므로 정적 파일 요청을 스스로 처리할 수 있다. 동적 파일에 대한 요청
을 받았을 때만 뒤쪽에 있는 서버와 커넥션을 할 수 있도록 하는 목적으로 개발되었다.
NginX는 master process
와 work process
가 있다. master process
는 설정 파일을 읽고, 설정에 맞게 work process를 생성하는 역할을 한다. work process
는 실제로 일을 하는 프로세스로, 생성 될 때 지정된 listen socket을 배정 받는다. 그리고 그 socket에 요청이 들어오면 해당 요청을 처리한다.
socket에 연결된 커넥션은 유지가 되지만, 요청이 들어오지 않는다면 새로운 커넥션을 형성하거나 다른 커넥션으로부터 요청을 처리한다. NginX에서는 이러한 커넥션 형성, 제거, 새로운 요청 처리
를 event
라고 부른다. 따라서 NginX가 이벤트 기반 구조
라고 불린다. 이러한 event들은 OS Kernel이 큐
형식으로 work process에 전달한다. 이들은 비동기 방식으로 대기
하고, 싱글 스레드로 이벤트들을 처리한다. 만약 요청 중 하나가 시간이 오래 걸린다면, 시간이 오래 걸리는 작업을 처리할 thread pool
을 만들어 해당 이벤트를 위임한다. thread pool은 cpu의 코어 개수만큼 생성된다.
이러한 구조는 서버 자원을 아파치보다 효율적으로 사용하게 된다. 이렇게 되면 context switching이 줄어든다. 따라서 동시 커넥션 양이 일반적으로 100~1000배 증가하며, 동일한 커넥션 수일 때 속도가 2배 향상된다.
NginX는 SSL 터미네이션
역할도 할 수 있다. SSL 터미네이션이란, 클라이언트와는 https connection
을 유지하며, 서버와는 http connection
을 유지하는 것을 말한다. 이 구조를 만들어 복호화 과정을 감당하지 않도록 해주며, http 프로토콜을 사용해 캐싱
할 수 있다.