Nginx 성능 튜닝: HTTP 처리 및 구성

12분 소요 - 2026년 5월 26일

hero section cover
목차
  • Nginx HTTP 처리 흐름: 구성 튜닝
  • Nginx가 HTTP 요청을 처리하는 방식
  • 작업자 프로세스 및 연결
  • 타임아웃 및 키프얼라이브
  • 버퍼 크기
  • 로드 밸런싱 및 업스트림 키프얼라이브
  • 테스트 및 모니터링
공유

단일 서버에서 초당 50,000개 이상의 요청을 처리하도록 Nginx 워커 프로세스, 버퍼, 킵얼라이브 및 로드 밸런싱을 조정합니다.

Nginx HTTP 처리 흐름: 구성 튜닝

Nginx의 기본 구성은 성능이 아닌 호환성을 위해 설계되었습니다. 적절한 튜닝을 통해 단일 서버가 초당 50,000~80,000건의 요청을 처리할 수 있습니다. 이 가이드에서는 워커 프로세스, 연결, 키프얼라이브, 버퍼링, 부하 분산 등 가장 중요한 설정 사항과 벤치마크를 통해 변경 사항을 검증하는 방법을 다룹니다.

Nginx가 HTTP 요청을 처리하는 방식

Nginx는 요청을 서로 다른 단계로 처리하며, 각 단계마다 시스템 리소스를 소비합니다. 이 흐름을 이해하면 적절한 설정을 적용하는 데 도움이 됩니다.

이 과정은 커널 수준에서 시작됩니다. 들어오는 연결은 SYN 및 ACCEPT 큐에 도착하며, Nginx 워커 프로세스가 이를 처리합니다. 수락되면 워커는 커널 버퍼에서 HTTP 요청을 파싱합니다. TLS 트래픽의 경우 이 단계에서 CPU 사용량이 더 많이 발생합니다.

다음으로, Nginx는 Host 헤더와 IP/포트 조합을 사용하여 요청을 가상 서버에 매칭한 후, 접두사 또는 정규식(regex) 매칭을 통해 URI를 location 블록으로 변환합니다.

동적 콘텐츠의 경우, Nginx는 요청을 백엔드(FastCGI, 프록시)로 전달합니다. 이 업스트림 통신 단계는 지속적 연결(persistent connections)을 통해 큰 이점을 얻습니다. 업스트림 keepalive가 없으면 Nginx는 요청마다 새로운 TCP 연결을 열게 되어 지연 시간과 CPU 오버헤드가 증가합니다.

if proxy_buffering 이 활성화되어 있으면, Nginx는 전체 업스트림 응답을 메모리에 읽어온 후 클라이언트에 전달합니다. 이를 통해 워커는 즉시 새로운 요청을 처리할 수 있게 됩니다. 마지막으로, 출력 전달 단계에서 sendfile 를 활성화하면 제로 카피 전송이 가능해져 처리량을 약 6 Gbps에서 30 Gbps로 끌어올릴 수 있습니다.

모든 단계에서는 메모리 버퍼, 파일 디스크립터 및 CPU 사이클이 소모됩니다. 아래 섹션에서는 각 병목 현상을 해결하는 방법을 다룹니다.

작업자 프로세스 및 연결

메인 컨텍스트에서 worker_processes auto; 로 시작하십시오. 이는 워커 수를 CPU 코어 수와 일치시킵니다. 코어가 제한된 VPS의 경우 수치를 수동으로 설정하십시오(예: worker_processes 2;). 메모리 집약적인 워크로드인 경우, RAM 과부하를 방지하기 위해 워커 수를 줄이는 것을 고려하십시오.

를 활성화하여 worker_cpu_affinity auto; 를 활성화하여 각 워커를 특정 코어에 고정하세요. 이렇게 하면 캐시 미스 및 컨텍스트 전환이 줄어듭니다. Nginx 1.9.10부터 사용 가능합니다.

연결 제한

` worker_connections 지시어는 각 워커가 처리할 수 있는 동시 연결 수를 설정합니다. 총 용량은 worker_processes × worker_connections입니다. 기본값인 512 또는 1,024는 실제 운영 환경에서는 너무 적습니다. 트래픽이 많은 사이트의 경우 워커당 2,048 또는 4,096으로 설정하십시오.

각 연결에는 최소한 하나의 파일 디스크립터가 필요합니다. 리버스 프록시 환경에서는 각 연결이 두 개(클라이언트용 하나, 업스트림용 하나)를 사용합니다. worker_rlimit_nofile 값보다 최소 두 배 이상으로 설정하십시오 worker_connections 값의 두 배 이상으로 설정하고 여유분을 확보하십시오. worker_connections 4096;의 경우 worker_rlimit_nofile 10000; 이상을 사용하십시오.

시스템 수준에서 fs.file-max 값을 /etc/sysctl.conf 값을 최소 500,000으로 늘리고 systemd의 LimitNOFILE=65535.

마지막으로, multi_accept on; events 블록에 추가하여, 워커가 대기 중인 연결을 한 번에 하나씩이 아니라 모두 한꺼번에 수락하도록 하십시오.

타임아웃 및 키프얼라이브

클라이언트 키프얼라이브

keepalive_timeout 지시어는 유휴 클라이언트 연결이 유지되는 시간을 제어합니다. 트래픽이 많은 서버의 경우 30~65초가 적절합니다. 두 개의 매개변수를 사용하는 형식을 사용하십시오:

keepalive_timeout 65s 60s;

첫 번째 값은 서버 측 타임아웃입니다. 두 번째 값은 클라이언트에 Keep-Alive: timeout=60 헤더를 클라이언트에 전송합니다. 클라이언트 값을 약간 낮게 설정하면, 브라우저가 Nginx가 이미 닫은 연결을 재사용하려는 경합 상황을 방지할 수 있습니다.

keepalive_requests 지시어는 단일 연결이 종료되기 전까지 처리할 수 있는 요청 수를 제한합니다. 기본값은 1,000입니다(버전 1.19.10에서 100에서 상향 조정됨). 안정적인 백엔드의 경우, 연결 전환을 줄이기 위해 이 값을 10,000으로 늘리십시오.

프록시 타임아웃

proxy_connect_timeout 는 Nginx가 백엔드와의 연결을 설정하기 위해 대기하는 시간을 설정합니다. 기본값은 60초입니다. 빠른 장애 조치(failover)를 위해 이 값을 5~10초로 줄이십시오.

proxy_read_timeout Nginx가 업스트림에서 연속적인 읽기 작업 사이에 대기하는 시간을 정의합니다. 백엔드의 실행 타임아웃과 일치하도록 설정하십시오. PHP-FPM의 request_terminate_timeout 120초인 경우, proxy_read_timeout 값을 최소 120초로 설정하여 조기 504 오류를 방지하십시오.

proxy_send_timeout 업스트림에 대한 연속적인 쓰기 작업 간의 간격을 제어합니다. 대용량 요청 본문을 전송하는 경우가 아니라면 기본값인 60초로 설정해도 일반적으로 문제없습니다.

일반적으로 proxy_connect_timeout 세 가지 중 가장 짧은 값으로 설정해야 합니다.

버퍼 크기

client_body_buffer_size 는 Nginx가 메모리에 저장하는 수신 요청 본문의 양을 제어합니다. 기본값인 8k 또는 16k는 간단한 양식 제출을 처리할 수 있지만, 파일 업로드 시 데이터가 디스크로 넘쳐나게 됩니다. 중소 규모의 업로드를 처리하려면 이 값을 128k로 늘리십시오. 사용자가 대용량 파일을 업로드할 경우 client_max_body_size 사용자가 더 큰 파일을 업로드하는 경우 기본값인 1MB에서 늘리십시오.

proxy_buffer_size 는 본문과 별도로 응답 헤더를 처리합니다. 기본값인 4k 또는 8k는 대개 충분하지만, 헤더 크기가 큰 애플리케이션의 경우 Set-Cookie (전자상거래에서 흔히 발생) 이 값을 초과하여 502 오류를 유발할 수 있습니다. 실제 헤더 크기를 측정하십시오:

curl -s -w '%{size_header}' -o /dev/null http://your-upstream-url

가장 가까운 4k 단위로 올림하십시오.

proxy_buffers 응답 본문을 위한 버퍼의 수와 크기를 설정합니다. 기본값(4k 또는 8k 버퍼 8개, 총 32k~64k)으로는 대용량 JSON 응답을 수용할 수 없습니다. curl 충분한 버퍼를 구성하여 전체를 RAM에 보관하십시오.

프록시 버퍼링 동작

proxy_buffering on (기본값)을 사용하면 Nginx는 전체 업스트림 응답을 메모리에 읽어들인 후 클라이언트로 전송합니다. 이를 통해 백엔드 서버는 즉시 새로운 요청을 처리할 수 있습니다.

proxy_busy_buffers_size 을 최소 proxy_buffer_size 버퍼 수량에 1을 더한 값 이상으로 설정하되, 전체 버퍼 풀 용량보다 작게 설정하십시오. proxy_buffers 8 16k (총 128k)인 경우 proxy_busy_buffers_size 112k 미만으로 유지하십시오.

Server-Sent Events나 롱 폴링과 같은 실시간 엔드포인트의 경우, 위치 지정 블록을 사용하여 버퍼링을 비활성화하십시오. proxy_buffering off 위치별 블록에서 비활성화하십시오. 이 설정을 /stream 또는 /events 경로에 선택적으로 적용하고, 전역적으로는 적용하지 마십시오.

로드 밸런싱 및 업스트림 키프얼라이브

기본적으로 Nginx는 프록시되는 각 요청마다 새로운 TCP 연결을 열게 됩니다. 각 핸드셰이크마다 10~100ms의 지연 시간이 발생하며, TLS를 사용할 경우 여기에 10~50ms가 추가됩니다. 업스트림 키프얼라이브는 이러한 오버헤드를 제거하기 위해 지속적 연결 풀을 유지합니다.

다음 세 가지 설정이 필요합니다:

upstream backend {
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    keepalive 128;
}
 
server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

` keepalive 값은 워커당 최대 유휴 연결 수를 설정합니다. 최적의 풀 크기는 다음과 같이 계산합니다: (workers × target concurrency) / upstream nodes.

upstream keepalive_timeout 값을 60~120초로 설정하여 백엔드 설정에 맞추고 트래픽 급증을 처리하십시오.

부하 분산 전략

Nginx는 여러 부하 분산 방법을 지원합니다. 라운드 로빈(기본값)은 요청을 순차적으로 분배합니다. least_conn 는 활성 연결 수가 가장 적은 서버로 라우팅하며, 이는 요청 지속 시간이 가변적인 워크로드에 적합합니다. ip_hash 동일한 클라이언트 IP를 동일한 백엔드로 라우팅하여 세션 지속성을 제공합니다.

서버의 용량이 서로 다른 경우 weight 매개변수를 사용하십시오:

upstream backend {
    least_conn;
    server 10.0.1.10:8080 weight=3;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080 backup;
    keepalive 128;
}

가중치가 부여된 서버는 3배의 트래픽을 수신합니다. backup 서버는 모든 주 서버가 다운된 경우에만 활성화됩니다. max_failsfail_timeout 를 수동 상태 확인용으로 설정하고, max_conns 를 사용하여 백엔드당 동시 연결 수를 제한하십시오.

테스트 및 모니터링

무언가를 변경하기 전에는 항상 기준 성능을 측정하십시오. 변경 후에는 매번 벤치마크를 다시 수행하십시오. 한 번에 한 가지 변경 사항만 적용하십시오.

재로드하기 전에 nginx -t 를 사용하여 구성 구문을 검증하십시오. 리소스 경합을 피하기 위해 별도의 머신에서 벤치마크를 실행하십시오.

wrk는 HTTP 부하 테스트를 위한 표준 도구입니다:

wrk -t4 -c200 -d30s http://your-server.com/

초당 요청 수, 평균 지연 시간, 최대 지연 시간 및 전송 속도를 추적하십시오. Apache Bench는 간단한 테스트에 적합합니다:

ab -n 50000 -c 40 http://your-server.com/

지속적인 모니터링

모듈을 활성화하여 stub_status 모듈을 활성화하여 curl http://localhost/nginx_status.

로그 형식에 타이밍 변수를 추가하여 지연이 발생하는 지점을 파악하세요:

  • $request_time 전체 요청 소요 시간
  • $upstream_connect_time 백엔드 연결 시간
  • $upstream_response_time 전체 백엔드 처리 시간

버퍼 문제를 확인하려면 오류 로그를 확인하십시오 journalctl -u nginx --no-pager | grep "temporary file". 응답이 디스크에 닿는다면, proxy_buffers 크기가 너무 작습니다. "열린 파일 수가 너무 많음(too many open files)" 오류를 확인하십시오. 이는 worker_rlimit_nofile 크기를 늘려야 함을 나타냅니다.

버퍼링 로깅을 사용하여 로그 I/O를 줄이십시오:

access_log /var/log/nginx/access.log combined buffer=64k flush=5s;

부하 테스트 중에 ss -tn state established dst [backend_ip] 부하 테스트 중에 연결이 재사용되고 TIME_WAIT 상태에 쌓이지 않는지 확인하십시오.

고성능 워크로드에 최적화된 전용 서버 및 VPS 호스팅에 대해서는 FDC 서버를 참조하십시오.

블로그

이번 주 추천

더 많은 기사
강력하고 계량되지 않는 VPS가 중요한 이유

강력하고 계량되지 않는 VPS가 중요한 이유

안정적인 성능과 무제한 트래픽이 필요하신가요? 강력한 무제한 VPS는 사용량 제한에 대한 걱정 없이 필요한 속도, 확장성, 대역폭을 제공합니다.

3분 소요 - 2025년 5월 9일

Linux에서 저장 공간을 최적화하는 방법

15분 소요 - 2026년 5월 22일

더 많은 기사
background image

질문이 있거나 맞춤형 솔루션이 필요하신가요?

icon

유연한 옵션

icon

글로벌 도달 범위

icon

즉시 배포

icon

유연한 옵션

icon

글로벌 도달 범위

icon

즉시 배포