Nginx worker와 upstream timeout

Nginx worker, connection, upstream keepalive, proxy timeout을 운영 관점에서 함께 정리한다.


Nginx가 버티는 지점

Client
  -> Nginx worker
     -> client connection
     -> upstream connection
  -> Tomcat / backend

Nginx는 이벤트 기반 Web Server다. 요청 처리량을 볼 때는 worker_processes, worker_connections, 파일 디스크립터 한계, upstream timeout을 함께 봐야 한다.

Apache HTTP Server가 MPM(Multi-Processing Module)과 worker 수를 보는 것처럼, Nginx는 worker process와 connection 수를 먼저 본다.

worker 기본값 읽기

설정의미운영에서 보는 질문
worker_processesworker process 개수CPU 코어와 트래픽 패턴에 맞는가
worker_connectionsworker 하나가 열 수 있는 connection 수client와 upstream 연결을 모두 포함해 충분한가
worker_rlimit_nofileworker의 파일 디스크립터 한계OS limit보다 낮게 막혀 있지 않은가
eventsconnection 처리 설정 context설정이 실제 nginx -T에 반영되는가
worker_shutdown_timeoutgraceful shutdown 대기 시간reload 때 기존 요청을 얼마나 기다릴 것인가

대략적인 connection 상한은 다음처럼 감을 잡는다.

전체 connection 여유 ~= worker_processes * worker_connections

다만 reverse proxy에서는 client 연결과 upstream 연결이 같이 생긴다. 단순히 클라이언트 동시 접속 수만 계산하면 부족할 수 있고, OS의 open files limit도 함께 확인해야 한다.

설정 예시

worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096;
}

http {
    include mime.types;

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://tomcat_backend;
        }
    }
}

worker_processes auto는 시작점으로 보기 좋지만, 실제 값은 CPU, SSL 처리량, 정적 파일 전송량, backend 지연 패턴에 따라 달라진다.

upstream 기본 구성

upstream tomcat_backend {
    server 10.0.0.11:8080 max_fails=3 fail_timeout=10s;
    server 10.0.0.12:8080 max_fails=3 fail_timeout=10s;
    keepalive 32;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://tomcat_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

upstream keepalive는 backend와의 idle 연결을 재사용한다. 연결 재사용은 비용을 줄일 수 있지만, Tomcat이 받을 수 있는 connection과 thread 여유보다 과하게 잡으면 backend 쪽을 압박할 수 있다.

timeout 값의 역할

설정의미흔한 증상
proxy_connect_timeoutbackend 연결을 맺을 때 기다리는 시간backend down, 방화벽, routing
proxy_send_timeoutbackend로 요청을 보내는 동안의 timeout큰 요청 body, 느린 backend 수신
proxy_read_timeoutbackend 응답을 읽는 동안의 timeout504, Tomcat thread/DB/API 지연
proxy_next_upstream실패 시 다음 upstream으로 넘길 조건재시도 여부, 중복 요청 위험
client_max_body_sizeclient 요청 body 크기 제한업로드 413

proxy_read_timeout을 늘리면 504가 줄어 보일 수 있다. 하지만 backend가 느린 원인이 사라지는 것은 아니다. Tomcat thread, DB slow query, 외부 API 지연을 함께 확인한다.

운영 예시

location /api/ {
    proxy_pass http://tomcat_backend;
    proxy_connect_timeout 3s;
    proxy_send_timeout 30s;
    proxy_read_timeout 60s;
    proxy_next_upstream error timeout http_502 http_503 http_504;
    proxy_next_upstream_tries 2;
    client_max_body_size 20m;
}

읽기 API와 쓰기 API를 같은 재시도 정책으로 묶지 않는다. 결제, 예약, 주문처럼 부작용이 있는 요청은 재시도로 중복 처리될 수 있으므로 애플리케이션의 idempotency 보장 여부를 같이 본다.

점검 명령

nginx -t
nginx -T | grep -n "worker_processes\|worker_connections\|proxy_read_timeout"
systemctl reload nginx
ss -s
ss -ant state established '( sport = :80 or sport = :443 )'
tail -f /var/log/nginx/error.log

OS limit 확인:

ulimit -n
cat /proc/$(pgrep -n nginx)/limits

운영에서는 nginx -T로 include된 최종 설정을 보는 습관이 중요하다. 설정 파일 하나만 보고 판단하면 다른 include 파일에서 같은 serverlocation이 덮고 있을 수 있다.

증상별 확인

증상확인 지점
worker_connections are not enoughworker_connections, open files limit, 연결 수
502backend port, firewall, process, upstream 설정
504proxy_read_timeout, Tomcat thread, DB/API 지연
reload 뒤 일부 요청 실패worker_shutdown_timeout, backend drain, 배포 타이밍
특정 node만 느림upstream node별 로그, health, Tomcat 상태
업로드 실패client_max_body_size, Tomcat upload limit

관련 문서

관련 블로그 기록

공식 문서

닫기 전 질문

  • worker_processes * worker_connections와 open files limit은 충분한가?
  • upstream keepalive가 Tomcat connection/thread 여유보다 과하지 않은가?
  • 504는 timeout 값 문제인가, backend 처리 지연의 결과인가?
  • 재시도 정책이 쓰기 요청에서 중복 처리를 만들 수 있지 않은가?