Nginx란?

고리·2022년 9월 14일
0

CS

목록 보기
3/6
post-thumbnail

Nginx is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache.

Nginx란 리버스 프록시, 로드밸런서, 메일 프록시, HTTP 캐시의 기능을 하는 웹서버다.

Nginx를 더 잘 이해하기 위해서는 Apache Web Server를 알아야 한다.


Apache Web Server의 등장

NCSA HTTPd라는 최초의 웹서버를 리눅스에서 돌리기 위해 만들어졌다.

Apache Web Server의 구조


아파치 웹 서버(이하 아파치)는 요청이 들어오면 connection을 만들기 위해 프로세스를 생성한다. 만약에 요청이 급격하게 늘어나면? 더 많은 connection을 만들기 위해 프로세스를 더 많이 생성한다.

connection은 3-way-handshake 방식을 통해 만들어진다. 이 방식을 통해 클라이언트와 서버 간의 connection이 설립되면 만들어진 통로를 사용해 요청과 응답이 오고 간다. 다시 말해 일단 connection이 형성되면 별다른 요청이 없어도 connection이 유지된다는 것이다. 이 부분을 꼭 기억해주길 바란다!!


하지만 프로세스를 만드는 시간이 오래 걸렸다. 그래서 요청이 들어오기 전에 미리 프로세스를 만들어 두고 요청이 들어올 때마다 만들어진 프로세스를 할당하는 Prefork방식을 사용하기 시작했다.

이러한 구조는 서버의 어느 지점에서든 모듈을 삽입할 수 있기 때문에 쉬운 개발그리고 뛰어난 확장성의 장점을 갖게 되었고, PHP와 같은 언어를 사용해 모듈을 만들어 삽입해 동적 컨텐츠 처리 또한 가능하게 되었다.

이러한 장점들 덕분에 서버 한 대에서 여러 요청을 처리할 수 있게 되었다. 그리고 아파치 서버가 등장한 때는 무어의 법칙이 절대적으로 작용하던 시기라 하드웨어 리소스마저 충분했다. 하지만 시간이 흐르면서 컴퓨터가 보급이 늘어나고 보급이 늘어나면서 요청이 늘어나고 요청이 늘어나면서 connection이 늘어나게 되었다.


그러자 이미 많은(약 10000개) connection이 서버에 연결되었을 때 다른 connection을 만들지 못하는 문제가 생겼다. 이것을 C10k problem이라 한다. 10K 이상의 context switching에 CPU는 허덕이고, 80년대에 10K 이상의 connection을 염두에 두지 않고 설계한 UNIX 소켓의 구조적 문제도 있었다.

더이상 커넥션이 연결되지 못하자 아파치를 통해 이 문제를 해결하려고 했다. 하지만 새로운 클라이언트로부터 요청이 들어올 때마다 connection을 만드는 아파치 웹 서버의 구조는 계속해서 CPU에 부담을 주게 되었고 아파치로는 이를 해결하지 못했다.

결국 개발자들은 아파치 서버 앞에 다른 방식으로 클라이언트의 요청을 처리하는 웹 서버를 위치시켰고 이 웹서버의 이름이 바로 Nginx다.


Nginx의 등장

보이는 그림처럼 아파치 서버 앞에 Nginx서버를 두고 사용자의 요청을 처리하게 했다. 그렇다면 Nginx는 어떤 구조로 되어 있길래 Apache Web Server가 하지 못한 일을 할 수 있는 걸까? 우선 비유를 통해 이해해보자


웹 서버 -> 식당


아파치라는 식당이 있다. 이 식당은 인기가 많아서 하루에 10000명의 손님이 찾아온다. 돈을 많이 벌었기 때문인지 손님의 전담 요리사도 존재한다. 여기서 문제는 요리사가 신입이라 한 번에 한 사람의 요리만을 할 수 있는 것이다. 100번 손님의 주문을 받아 요리를 마치면 101번 손님의 주문을 받아 요리를 만들어 준다. 이 식당의 문제는 다음과 같다.

  1. 만약 103번 손님이 바로 낚은 광어회를 요청하면 가스렌지가 비었음에도 104번 전담 요리사는 기다려야 한다.
  2. 103번 요리사가 요리하는 동안 103번을 제외한 다른 요리사 9999명은 일을 안 하고 놀고 있다.
  3. 요리사가 너무 많아서 순서대로 재료를 주는 것에도 시간이 오래 걸린다.

Nginx 식당은 바로 이 점을 해결했다.

Nginx 식당은 전담 요리사 제도를 없애고 한정된 수(ex: 8명)의 만능 요리사를 고용해 10000명의 주문을 처리한다. 이로써 위의 세 가지 문제가 해결되었다.

  1. 만능 요리사이기 때문에 낚시하면서 104번 요리를 할 수 있다.
  2. 10000명에서 8명으로 요리사가 줄었기 때문에 월급이 덜 나간다.
  3. 요리사가 8명에게 순서대로 재료를 금방 줄 수 있다.

식당 -> 웹 서버

아파치라는 웹 서버가 있다. 이 서버는 인기가 많아서 하루에 10000명의 클라이언트가 connection을 요청한다. 각 connection을 전담하는 process가 존재한다. 여기서 문제는 이 process들은 한 번에 하나의 connection만 처리할 수 있는 것이다. 100번 connection의 request 처리가 끝나면 101번 connection의 request를 처리한다. 이 서버의 구조적 문제는 다음과 같다.

  1. 103번 connection이 CPU를 사용하지 않는 I/O 요청을 보내면 CPU를 사용할 수 있지만 104번 connection의 요청에 응답할 수 없다. 이것을 Blocking이라 한다.
  2. 103번 process가 request에 응답하는 동안 다른 9999개의 process는 connection을 유지하기 위해 추가 리소스가 필요하고 이 리소스들은 낭비되는 overhead다.
  3. process가 너무 많아서 context-switching에 걸리는 시간이 크다.

Nginx라는 웹 서버는 바로 이점을 해결했다. connection‑per‑process(커넥션당 프로세스 1개)에서 벗어나 CPU코어 수와 같은 수의 Worker Process를 사용해 10000개의 Request를 처리한다. 이로써 위의 세 가지 문제가 해결되었다.

  1. worker process는 Non-Blocking방식으로 동작해 103번 connection의 request와 104번 request를 동시에 처리할 수 있다.
  2. process를 적게 만들기 때문에 process할당에 필요한 컴퓨팅 리소스가 적다.
  3. process가 적기 때문에 상대적으로 context-switching에 걸리는 시간이 적다.

결과적으로 Nginx는 하드웨어 리소스를 적게 사용할 수 있었다. 바로 이 특징이 Nginx가 Apache Web Server와는 달리 10K이상의 커넥션을 감당할 수 있게 했다.


Nginx의 구조

nginx.com에 가보면 Nginx의 아키텍처를 볼 수 있다. Nginx는 특별한(Privileged) 작업을 수행하는 Master Process를 갖고 있다.

Master process는 다음의 작업을 한다.

1. listen socket에 port를 바인딩
2. Nginx설정 읽고 유효성 검사
3. worker, cache loader, cache manager 3가지 자식 프로세스 생성 (중요!!!)

3번 작업에 의해 Nginx의 구조가 위의 사진과 같은 것이다. 이제 worker process를 눈여겨보자. 이 프로세스는 네트워크 접속 처리, DISK 입출력, 업스트림 서버(서버 계층에서 상위에 있는 서버)와 통신 등 생각할 수 있는 거의 모든 작업을 해내는데 그 특징은 다음과 같다.

  1. 이 모두를 싱글 스레드로 처리
  2. 각 worker process는 non-blocking 방식으로 클라이언트의 connection을 처리
  3. 하드웨어 리소스의 효율적인 사용을 위해 CPU의 코어 1개당 1개씩 생성 -> context-switching 비용 감소

Worker Process

클라이언트로부터 요청이 들어와 connection을 생성하고 요청을 처리하고 connection을 종료하는 과정들을 Nginx는 Event라고 한다. 우리의 Worker Process는 listen socket을 열어두고 위의 Event를 기다린다. conenction 생성 Event가 발생하면 State Machine(Nginx가 요청을 처리하는 명령어 집합)으로 전달한다.

Worker process는 active한 connection을 단 하나만 생성할 수 있기 때문에 해당 요청이 끝나면 connection을 종료한다. 이 connection들은 worker process안에서 최소한의 메모리를 사용한다. CPU의 코어 개수로 할당되는 이 worker process들은 CPU에 고정된다. 이렇게 함으로써 Cache Warm을 통해 Cache Hit Rate를 올려 Process의 속도를 더 높일 수 있고 해당 프로세스에서 수행할 작업이 없을 때만 Context-switching이 발생하기에 오버헤드도 상대적으로 적다.

이러한 Nginx의 구조가 Event-driven이며 Apache Web Server와 가장 큰 차이점이다.

단점

아파치 웹 서버는 모듈 삽입으로 쉬운 기능 추가가 가능했다. 하지만 Nginx는 기능 추가를 시도하다가 동작중인 Worker Process를 종료할 수 있어 기능 추가가 쉽지 않고 모듈도 상대적으로 적다. 이 때문에 모듈 추가로 인한 확장성은 아파치 웹 서버에 비해 다소 떨어진다.

하지만 이러한 단점을 전부 상회할 수 있는 압도적인 성능을 Nginx가 가지고 있기에 Apache Web Server의 점유율을 꾸준히 뺏어오고 있다.

Windows지원은 약하지만 성능이라는 장점으로 트래픽이 많은 웹 사이트에 적합하고 가벼워 확장성 또한 뛰어나다.

다음 포스트에서는 Nginx서버를 만들어 보자


ref
https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/
https://rootkey.tistory.com/143
https://www.youtube.com/watch?v=6FAwAXXj5N0
https://www.redhat.com/sysadmin/tune-linux-tips

profile
Back-End Developer

0개의 댓글