
과거, 대학시절 2학년 2학기를 종강하고 대학 동기와 42seoul의 webserv라는 프로젝트를 진행하기로 했다. 이 webserv 프로젝트의 요구사항은 nginx와 같이 I/O Multiplexing 기술을 활용한 서버를 만드는 과제이다.
HTTP 프로토콜 기반이기에 HTTP 관련 RFC723X 문서들을 읽고나서 이게 내가 읽는 것인지 읽힘을 당하고 있는지 모르는 듯 읽어나갔다. 그것보다 양이 엄청나다..
이후 많은 학습과 더불어 설계를 진행하고 대략적인 프로젝트를 진행하다 학부 생활과 병행하는 것이 한계가 있어 무산되었다...
이후 4학년이 끝날 무렵 지금까지 해온 프로젝트에 Nginx 사용이 종종 있었다. 이에 Nginx가 무엇인지 정리하려 한다.
A -> B : A가 B를 호출했다고 가정
요청을 보낸 후, 그 작업이 완료될 때 까지 아무것도 하지 않고 기다려야 하는 상태이다.
요청을 보낸 후, 요청이 끝날 때까지 기다릴 필요 없이 다른 일을 할 수 있는 상태이다.
작업이 순서대로 진행되며, 요청이 완료되면 응답을 확인하거나 작업이 끝나는 시점을 직접 확인한다. 이는 작업이 일련의 순서를 따르며 작업의 순서가 보장된다. (작업의 순서를 보장한다는 것은 '현재 작업의 응답'을 받는 시점과 '다음 작업을 요청'하는 시점을 맞추는 것이다. 다음 작업 자체가 순서가 있다는 것을 의미하고, 이전 작업이 완료되기 전까지 다음 작업이 수행되지는 않는다. )
blocking과의 혼동을 느낄 수 있는데 blocking 되는 동안 다른 작업이 끼어들 수 있냐 없냐의 문제를 보면 순서의 개념으로 sync/Async와 관련된다 보면 된다.
작업이 진행되는 동안 요청자가 따로 확인할 필요 없이, 완료되면 알아서 결과를 알려준다. 작업 순서를 고려하지 않고 동시에 작업이 가능하다.
synchronous & blocking: A가 B의 작업을 기다리며 상태를 계속 확인. B가 완료될때 까지 A는 다른 작업 불가
synchronous & non-blocking: A는 B의 작업을 기다리지 않고 A의 일을 하면서, A는 B의 작업 상태를 계속해서 확인
asynchronous & blocking: A는 B의 작업을 기다림. B는 작업이 완료되면 A에게 결과 전달.
asynchronous & nonblocking: A는 B의 작업을 기다리지 않고 A의 일을 함. 그러던 중 B는 A에게 작업 결과를 전달.
block, non-block: 현재 작업이 차단되는가에 관점
synch, asynch: 작업이 순차적인가에 관점
사용자, 서버, 운영체제 등의 관점에 따라 블로킹, 논블로킹, 동기, 비동기가 달라질 수 있다.
I/O 작업은 단순 단일 server 내에서 일어나는 읽기/쓰기 뿐만 아니라 server-Client간 네트워크 통신에도 적용되는 개념이다. I/O Multiplexing은 각 모델중 하나이다.
다중화 작업으로 여러 I/O 작업을 독립적으로 관리하는 방법이다.
각각의 요청은 blocking 되지만, 비동기적으로 여러 소켓이 동시에 동작합니다. 소켓 작업이 완료되면 event처럼 callback을 전달하는데, 서버에서는 전체 callback을 하나로 관리하고 완료된 소켓을 찾아 후속 작업을 처리합니다. 즉, (epoll, kqueue, select) 다중 접속 처리에 관여한다.
WS(Web Server) : 클라이언트의 요청에 따라 적절한 자원을 전달해준다. (Apache, Nginx)
WAS(Web Application Server) : 웹서버의 부하분산을 위해 더 고도화된 서버. (Tomecat)
정적 자원, 동적 자원의 차이로 보는 시각도 있지만 JSP, PHP 등 동적 컨텐츠 생성 플러그인을 지원하여 WS/WAS 모두 동적 데이터 전달이 가능하다.
과거 멀티쓰레드를 사용하던 시절에는 Blocking I/O 방식 처리를 진행하였다. 그렇기에 동시적으로 많은 작업을 처리하는것에 있어 부적합 하였다. 즉, 요청이 많을 수록 작업 처리 방식이 무겁고, 오랜 시간이 소요된다.
멀티 쓰레드: 하나의 프로그램에 동시에 여러 작업을 진행, 프로세스 하나의 자원을 공유하여 처리 속도가 빠르지만, 한정된 자원을 쪼개서 사용하기에 쓰레드별로 자원을 효율적으로 분배해야 한다.
apache에도 Non-blocking 모델이 존재한다
사전에 서버 개발자가 쓰레드 개수를 생성(Thread pool)하고, 해당 쓰레드 풀 내에 한정된 쓰레드 풀만을 가지고 HTTP 요청에 대한 작업을 처리한다.
nginx는 하나의 프로세스에서 여러개의 클라이언트와의 통신을 처리가 가능하고, 내부적으로 커널 큐를 사용해 작업의 순서를 보장함. 매우 큰 작업이 발생 시 해당 작업만 따로 쓰레드 풀에 넣어서 관리한다.
하나의 마스터 프로세스에서 여러개의 워커 프로세스를 통해 이벤트 기반 처리를 활용하여 비동기 Non-Blocking 방식으로 프로세스 작업이 끝날 때까지 대기하지 않는다.

설정 방식은 nginx 공식 문서에 잘 나와있다.
[nginx 공식문서] https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/
리버스 프록시로 서버 앞단에 배치하여 게이트웨이 역할을 통해 보안적인 측면에서 활용 가능하다.

HTTP 프로토콜을 사용해서 전달되는 컨텐츠를 캐싱할 수도 있다. 이 외에도 HSTS(HTTP Strict Transport Security), CORS(Cross-Origin Resource Sharing)처리, TCP/UDP 커넥션 부하 분산, HTTP/2 등의 일을 한다.
Nginx가 트래픽을 분산 처리하여 Apache 서버 확장 가능하며, Nginx를 앞단에 필터 역할을 통해 보안적 강화가 가능하고, 터미네이션과 같이 성능 최적화가 가능하다.