Nginx의 핵심 기능과 동작 아키텍처

Nginx의 주요 기능

Nginx는 웹 트래픽을 효율적으로 관리하고 최적화하기 위해 설계된 고성능 오픈소스 웹 서버입니다. 단순한 웹 서버 기능을 넘어 다양한 고급 기능들을 제공합니다.
  • 리버스 프록시 (Reverse Proxy)
  • 포워드 프록시 (Forward Proxy)
  • 로드 밸런싱 (Load Balancing)
  • HTTP 서버 (정적/동적 자원 분리 포함)

프록시 서버 이해: 리버스 vs. 포워드

프록시는 클라이언트와 서버 사이에서 중개자 역할을 수행하는 서버를 의미합니다. 크게 포워드 프록시와 리버스 프록시로 나눌 수 있습니다.

포워드 프록시 (Forward Proxy)

포워드 프록시는 클라이언트 대신 특정 웹 서버에 요청을 전달하는 방식입니다. 예를 들어, 특정 웹사이트에 직접 접근할 수 없는 환경(방화벽 내부 등)에서 클라이언트는 포워드 프록시 서버에 접속한 후, 프록시를 통해 원하는 웹사이트의 콘텐츠를 요청합니다. 이때 웹사이트는 요청이 프록시 서버로부터 온 것으로 인식합니다. 클라이언트가 프록시 설정을 명시적으로 해야만 사용할 수 있습니다. 주요 사용 사례는 인터넷 접근 제어, 캐싱을 통한 네트워크 사용량 절감 등이 있습니다.

리버스 프록시 (Reverse Proxy)

리버스 프록시는 웹 서버 앞에 위치하여 클라이언트의 요청을 받아 실제 백엔드 서버로 전달하는 방식입니다. 클라이언트는 리버스 프록시 서버를 마치 최종 웹 서버처럼 인식하며, 실제 콘텐츠를 제공하는 백엔드 서버의 존재나 위치를 알 필요가 없습니다. 리버스 프록시는 요청을 받아 적절한 백엔드 서버로 라우팅하고, 응답을 받아 클라이언트에게 전달합니다. 이 방식은 보안 강화, 로드 밸런싱, 캐싱, SSL 암호화 처리 등에 널리 사용됩니다.

요약

  • 포워드 프록시: 클라이언트가 최종 서버에 직접 접근하기 어려울 때, 클라이언트의 요청을 대리하여 전달합니다. 클라이언트 관점에서 프록시가 작동합니다.
  • 리버스 프록시: 클라이언트의 요청을 받아 백엔드 서버로 전달하고 결과를 반환합니다. 클라이언트 관점에서 리버스 프록시는 실제 서버처럼 보입니다.

로드 밸런싱

로드 밸런싱은 Nginx의 핵심 기능 중 하나로, 여러 개의 서버에 트래픽을 분산하여 시스템의 성능, 가용성 및 확장성을 향상시키는 기술입니다. Nginx는 기본적으로 여러 로드 밸런싱 알고리즘을 지원하며, 특정 모듈을 통해 추가적인 방법을 활용할 수 있습니다.

Nginx 내장 로드 밸런싱 알고리즘

  1. 라운드 로빈 (Round Robin): 가장 기본적인 방식으로, 각 요청을 시간 순서대로 백엔드 서버에 균등하게 분배합니다. 별도의 설정이 없으면 Nginx는 이 방식을 기본으로 사용합니다. 서버 중단 시 자동으로 해당 서버를 제외합니다.
  2. 가중치 기반 (Weighted Round Robin): 각 백엔드 서버에 가중치(weight)를 부여하여, 서버의 처리 능력에 비례하여 요청을 분배합니다. 성능이 좋은 서버에는 더 많은 요청을 할당할 수 있습니다.
    upstream backend_web_apps {
        server app_server_a:8001 weight=7;
        server app_server_b:8002 weight=3;
    }
    
    위 예시에서는 `app_server_a`가 `app_server_b`보다 7배 더 많은 요청을 처리하게 됩니다.
  3. IP 해시 (IP Hash): 클라이언트의 IP 주소를 해시하여 특정 백엔드 서버로 고정적으로 연결합니다. 이는 사용자의 세션 정보가 특정 서버에만 저장되는 '상태 저장(stateful)' 애플리케이션 환경에서 세션 일관성을 유지하는 데 유용합니다.
    upstream user_sessions {
        ip_hash;
        server web_node_1:8080;
        server web_node_2:8081;
    }
    
  4. 최소 연결 (Least Connection): 가장 적은 활성 연결을 가지고 있는 백엔드 서버로 요청을 분배합니다. 이는 서버의 현재 부하 상태를 고려하여 트래픽을 더 효율적으로 분산할 수 있게 합니다.
    upstream dynamic_apps {
        least_conn;
        server app_instance_1:9000;
        server app_instance_2:9001;
        server app_instance_3:9002;
    }
    

추가적인 로드 밸런싱 방식 (모듈 활용)

Nginx는 추가 모듈을 통해 최소 응답 시간 기반 분배(fair)나 URL 해시 기반 분배(url_hash)와 같은 더 정교한 로드 밸런싱 방식을 구현할 수 있습니다. 이는 특정 캐싱 전략이나 성능 최적화가 필요할 때 활용됩니다.

HTTP 서버 기능

Nginx 자체는 고성능 HTTP 서버의 역할도 수행합니다. 특히 정적 파일(HTML, CSS, JavaScript, 이미지 등)을 효율적으로 서빙하는 데 강점을 가집니다. 최근에는 '정적/동적 자원 분리(Static-Dynamic Separation)' 아키텍처가 널리 사용되는데, 이는 웹사이트의 변하지 않는 자원(정적)과 사용자 요청에 따라 변하는 자원(동적)을 구분하여 처리하는 방식입니다. Nginx는 정적 자원을 직접 처리하고, 동적 자원 요청은 리버스 프록시를 통해 백엔드 애플리케이션 서버로 전달함으로써, 전체 시스템의 응답 속도와 효율성을 크게 향상시킬 수 있습니다. 정적 자원에 대한 캐싱 정책을 Nginx에서 관리하여 성능을 더욱 최적화할 수도 있습니다.

Nginx 프로세스 모델

Nginx는 마스터-워커(Master-Worker) 프로세스 모델을 기반으로 동작합니다. Nginx가 시작되면 하나의 마스터 프로세스와 여러 개의 워커 프로세스가 생성됩니다.

마스터 프로세스

마스터 프로세스는 Nginx 시스템 전체를 관리하는 역할을 담당합니다. 주요 기능은 다음과 같습니다.
  • 워커 프로세스 생성, 관리 및 모니터링
  • 외부 신호(signal) 수신 및 워커 프로세스로 전달 (예: 설정 파일 재로드, 서버 종료)
  • 워커 프로세스 비정상 종료 시 새로운 워커 프로세스 자동 재시작
  • 설정 파일 실시간 적용, 서비스 중단 없는 재시작(graceful restart) 등의 작업을 총괄
예를 들어, `nginx -s reload` 명령을 실행하면, Nginx는 새로운 Nginx 프로세스를 시작하고, 이 프로세스는 마스터 프로세스에게 재로드 신호(HUP)를 보냅니다. 마스터 프로세스는 이 신호를 받아 새로운 설정 파일을 로드하고 새로운 워커 프로세스들을 시작합니다. 이어서 기존의 워커 프로세스들에게는 모든 현재 요청을 처리한 후 종료하라는 신호를 보냅니다. 이 과정을 통해 서비스 중단 없이 설정 변경이 이루어집니다.

워커 프로세스

워커 프로세스는 실제 클라이언트 요청을 처리하는 핵심적인 역할을 수행합니다.
  • 클라이언트 연결 수락 및 요청 처리
  • 요청 구문 분석, 데이터 처리 및 응답 전송
  • 마스터 프로세스로부터 독립적으로 동작하며, 각 워커 프로세스는 다른 워커 프로세스의 요청에 영향을 미치지 않음
일반적으로 워커 프로세스의 개수는 서버의 CPU 코어 수와 동일하게 설정하는 것이 권장됩니다. 모든 워커 프로세스는 마스터 프로세스로부터 `fork`되어 생성되며, 동일한 리스닝 소켓을 공유합니다. 새로운 연결 요청이 들어올 때, 워커 프로세스들은 `accept_mutex`라는 잠금 메커니즘을 사용하여 하나의 워커 프로세스만이 해당 연결을 수락하도록 보장합니다. 연결을 수락한 워커 프로세스는 해당 요청의 모든 단계를 처리하고 클라이언트에게 응답을 보낸 후 연결을 종료합니다.

멀티 프로세스 I/O 모델의 장점

Nginx의 멀티 프로세스 모델은 다음과 같은 이점을 제공합니다.
  • 독립성 및 안정성: 각 워커 프로세스는 독립적으로 동작하므로, 하나의 워커 프로세스에 문제가 발생하더라도 전체 서비스에 영향을 주지 않고, 마스터 프로세스가 새로운 워커를 즉시 재시작하여 서비스 연속성을 보장합니다.
  • 오버헤드 감소: 워커 프로세스 간에 잠금(lock)이 필요 없어 동기화에 필요한 오버헤드가 줄어들며, 개발 및 디버깅이 용이합니다.
  • 자원 효율성: 각 워커는 CPU 코어에 바인딩되어 컨텍스트 스위칭 비용을 최소화하며, 효율적인 CPU 활용을 가능하게 합니다.

Nginx의 비동기 논블로킹 이벤트 모델

Nginx가 높은 동시성을 처리할 수 있는 핵심 비결은 비동기 논블로킹(Asynchronous Non-blocking) I/O 모델에 있습니다. 각 워커 프로세스는 단일 스레드 구조를 가지지만, I/O 작업(예: 네트워크 데이터 읽기/쓰기)에서 블로킹되지 않고 이벤트를 기반으로 동작합니다. 기존의 일부 웹 서버 모델(예: Apache의 Prefork 모델)에서는 하나의 요청에 하나의 프로세스 또는 스레드가 할당되어 I/O 작업 중 해당 프로세스가 대기(블로킹) 상태에 들어갑니다. 이는 많은 동시 요청 발생 시 수많은 프로세스/스레드가 생성되어 시스템 리소스 소모 및 컨텍스트 스위칭 오버헤드를 유발하여 성능 저하로 이어집니다. 반면 Nginx의 워커 프로세스는 요청이 들어오면 I/O 작업이 준비될 때까지 기다리지 않고 즉시 다른 작업을 수행합니다. I/O 이벤트가 발생하면(데이터를 읽거나 쓸 수 있게 되면) 해당 이벤트를 처리합니다. 이러한 비동기 논블로킹 방식은 단일 워커 프로세스가 수천, 수만 개의 동시 연결을 효율적으로 처리할 수 있게 합니다. 워커 프로세스는 대기 상태에 거의 들어가지 않으므로 CPU를 최대한 활용하고, 컨텍스트 스위칭 비용을 최소화하여 뛰어난 성능과 확장성을 제공합니다.

태그: nginx 리버스 프록시 로드 밸런싱 HTTP 서버 비동기 I/O

7월 27일 07:02에 게시됨