Post

Nginx

1. Nginx

Nginx(엔진엑스)는 웹 서버 소프트웨어로, 가벼움과 높은 성능을 목표로 한다. 웹 서버, 리버스 프록시 및 메일 프록시 기능을 가진다.

nginx

Nginx는 요청에 응답하기 위해 비동기 이벤트 기반 구조를 가진다. 이것은 아파치 HTTP 서버의 스레드/프로세스 기반 구조를 가지는 것과는 대조적이다. 이러한 구조는 서버에 많은 부하가 생길 경우의 성능을 예측하기 쉽게 해준다.

2. Nginx 특징

Nginx는 싱글 프로세스 스레드로 이벤트 구동에 의한 넌블로킹(Non-Blocking) 처리를 하므로 처리속도가 매우 빠르다. 그러나 넌블로킹 처리에 따라 프로그램의 제어가 이벤트 핸들러(Event Handler)로 넘어왔다고 해도 실제 데이터를 읽고 쓰는 건 OS(커널) 내에 있는 시스템 호출 프로그램과 하드웨어 사이에서 실행되므로, I/O 시간이 길어지면 결국 시스템 호출 큐에 요청이 많이 쌓여 성능이 저하될 수 있다.

따라서 nginx는 매우 작은 데이터를 대량으로 전송하는 서버나, 하드디스크 읽기와 쓰기가 발생하지 않는 In-memory Cache Server/Reverse Proxy Server/Front-end Load Balancer와 같은 역할에 적합하다. 반대로 매우 복잡한 CGI 처리, 동영상 데이터 전송, 데이터베이스 처리를 실행하는 데는 적합하지 않다.

Apache는 과거 java servlet이 대중적이지 않던 시절 CGI를 통한 웹서비스를 위해 생겨났기 때문에 Process-Base 방식이고, Nginx의 경우 Http Proxy의 목적으로 생겨났기 때문에 Event-Base 방식이다.

3. Nginx와 Apache 차이점

Nginx는 Apache 이후 서버 환경에 도입되었으며, 따라서 개발자들은 Apache가 가지고 있는 웹 서비스 문제와 기술적 한계를 인식할 수 있는 이점이 있다.

이러한 문제와 한계를 직접 해결을 위해 Nginx는 이벤트 기반 비동기식 단일 스레드 아키텍처를 사용한다. 리눅스 및 유닉스 같은 최신 운영 체제의 기본 기능을 활용하여, Nginx는 Apache에 비해 서버당 최소 10배 이상(대개 100~1000배 이상)의 요청을 처리할 수 있다. 메모리와 CPU의 사용을 효율적으로 최적화하면서, Nginx는 더 많은 사용자 연결을 제공하는 동시에 더 나은 대역폭을 제공하며 다른 최신 운영 체제에 비해 리소스 소모가 적다.

Nginx는 Apache와는 다르게 요청을 처리하므로 다양한 역할을 가진 보다 동적인 환경에 적합하다. 동적 웹 콘텐츠를 제공하는 것 외에 웹 응용 프로그램에서 Nginx를 위한 가장 인기 있는 사용 사례 시나리오로는 HTTPS 및 기타 TCP 프로토콜을 위한 역방향 프록시 서버 사용, 효율적인 트래픽 배포를 위한 로드 밸런싱, HTTP 캐싱 등이 있다.

Apache를 로드 밸런싱 장치로 사용할 수 있지만, Apache는 성능과 내구성으로 잘 알려져 있으며, Nginx는 속도, 응답성 및 리소스 효율성으로 잘 알려져 있다. 따라서 백엔드 서버로 Apache를 사용하고 역방향 프록시로 NGINX를 사용하는 것이 훨씬 더 일반적이다.

4. 동적 요청 처리

1) Apache

아파치를 훌륭하게 만드는 것 중 하나는 MPM 또는 ‘멀티 프로세싱 모듈’을 사용한 모듈식 구성이다. Apache는 기존의 파일 기반 방법과 MPM 작업자를 통해 정적 및 동적 콘텐츠를 완벽하게 처리할 수 있다. 필요한 언어 프로세서를 각 작업자 인스턴스에 포함시킴으로써, 동적 컨텐츠는 외부 구성요소에 의존하지 않고 서버 내에서 실행될 수 있다.

2) Nginx

자체적으로 Nginx는 동적 콘텐츠를 기본적으로 처리할 수 없습니다. PHP와 같은 스크립팅 언어를 처리하려면, Nginx는 스크립트 실행을 처리하는 외부 프로세서로 요청을 전달한 후 최종 사용자에게 콘텐츠가 전송되고 렌더링되고 제공될 준비가 될 때까지 기다려야 한다. 즉, 관리자는 http, FastCGI, SCGI 및 uWSGI와 같이 Nginx가 사용하는 프로토콜을 통해 통신을 구성해야 한다.

동적 인터프리터는 외부이며 작업자 프로세스와 통합되어 있지 않기 때문에 정적 콘텐츠를 직접 제공할 수 있는 동안 동적 콘텐츠를 제공하는 데만 사용된다. 이로 인해 Nginx는 속도와 응답성이라는 명성을 얻게 된다.

5. Network Programming

1) Native Threads

전통적인 서버는 스레드 프로그래밍이라는 기술을 사용한다. 이 아키텍처에서 각 연결은 단일 프로세스 또는 기본 스레드(OS 스레드라고도 함)에 의해 처리된다.

이 아키텍처는 프로세스 또는 네이티브 스레드를 만드는 데 사용되는 메커니즘을 기반으로 더욱 세분화될 수 있다. 스레드 풀을 사용할 경우 여러 프로세스 또는 기본 스레드가 미리 생성된다.

그 예로는 Apache의 prefork 모드가 있다. 그렇지 않으면 연결이 수신될 때마다 프로세스 또는 기본 스레드가 생성된다.

native-threads

이 아키텍처의 장점은 개발자가 명확한 코드를 작성할 수 있다는 것이다. 특히 스레드의 사용은 코드가 간단하고 친숙한 제어 흐름을 따르고 간단한 프로시저 호출을 사용하여 입력을 가져오거나 출력을 전송할 수 있도록 한다. 또한 커널이 프로세스 또는 네이티브 스레드를 사용 가능한 코어에 할당하기 때문에 코어 활용률의 균형을 맞출 수 있다.

커널과 프로세스 간에 많은 컨텍스트 전환 또는 네이티브 스레드가 발생하여 성능이 저하된다는 것이 단점이다.

2) Event-driven Architecture

고성능 서버의 세계에서는 최근 이벤트 중심 프로그래밍을 활용하는 추세이다. 이 아키텍처에서 다중 연결은 단일 프로세스에 의해 처리된다. Lighttpd는 이 아키텍처를 사용하는 웹 서버의 예이다.

event-driven-architecture

프로세스를 전환할 필요가 없기 때문에 컨텍스트 스위치가 적게 발생하고 성능이 향상된다. 이것이 주된 장점이다.

반면에, 이 아키텍처는 네트워크 프로그램을 상당히 복잡하게 만든다. 특히, 이 구조는 이벤트 루프가 프로그램의 전반적인 실행을 제어하도록 제어의 흐름을 반전시킨다. 그러므로 프로그래머는 프로그램을 이벤트 핸들러로 재구성해야 하며, 각 이벤트 핸들러는 비차단 코드만 실행한다.

이 제한은 프로그래머가 프로시저 호출을 사용하여 I/O를 수행할 수 없도록 한다. 대신 더 복잡한 비동기 메소드를 사용해야 한다. 기존의 예외 처리 방법을 더 이상 적용할 수 없다.

3) One Process Per Core

N 코어를 활용하기 위한 N개의 이벤트 중심 프로세스를 만들자는 의견이 많이 제기되었다. 각 프로세스를 작업자라고 한다. 서비스 포트는 작업자 간에 공유되어야 한다. prefork 기술을 사용하여 포트 공유가 가능하다.

기존 프로세스 프로그래밍에서는 연결이 승인된 후 새 연결에 대한 프로세스가 분기된다. 이와는 대조적으로, prefork 기술은 새로운 연결이 승인되기 전에 프로세스를 포크한다. 공유된 이름에도 불구하고, 이 기술은 Apache의 prefork 모드와 혼동되어서는 안 된다.

one-process-per-core

이 아키텍처를 사용하는 웹 서버 중 하나는 nginx이다. Node.js는 과거에 이벤트 기반 아키텍처를 사용했지만 최근에는 prefork 기법도 구현했다.

이 아키텍처의 장점은 모든 코어를 활용하고 성능을 향상시킨다는 것이다. 그러나 핸들러 및 콜백 함수에 대한 의존으로 인해 프로그램의 명확성이 떨어지는 문제는 해결하지는 못한다.

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.