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_processes | worker process 개수 | CPU 코어와 트래픽 패턴에 맞는가 |
worker_connections | worker 하나가 열 수 있는 connection 수 | client와 upstream 연결을 모두 포함해 충분한가 |
worker_rlimit_nofile | worker의 파일 디스크립터 한계 | OS limit보다 낮게 막혀 있지 않은가 |
events | connection 처리 설정 context | 설정이 실제 nginx -T에 반영되는가 |
worker_shutdown_timeout | graceful 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_timeout | backend 연결을 맺을 때 기다리는 시간 | backend down, 방화벽, routing |
proxy_send_timeout | backend로 요청을 보내는 동안의 timeout | 큰 요청 body, 느린 backend 수신 |
proxy_read_timeout | backend 응답을 읽는 동안의 timeout | 504, Tomcat thread/DB/API 지연 |
proxy_next_upstream | 실패 시 다음 upstream으로 넘길 조건 | 재시도 여부, 중복 요청 위험 |
client_max_body_size | client 요청 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 파일에서 같은 server나 location이 덮고 있을 수 있다.
증상별 확인
| 증상 | 확인 지점 |
|---|---|
worker_connections are not enough | worker_connections, open files limit, 연결 수 |
| 502 | backend port, firewall, process, upstream 설정 |
| 504 | proxy_read_timeout, Tomcat thread, DB/API 지연 |
| reload 뒤 일부 요청 실패 | worker_shutdown_timeout, backend drain, 배포 타이밍 |
| 특정 node만 느림 | upstream node별 로그, health, Tomcat 상태 |
| 업로드 실패 | client_max_body_size, Tomcat upload limit |
관련 문서
관련 블로그 기록
- NGINX 부하분산 (HTTP / TCP) — Nginx upstream 구성 사례
- LB·WAF 뒤에서 클라이언트 실제 IP 살리기 — 프록시 헤더와 실제 IP 추적 사례
공식 문서
닫기 전 질문
worker_processes * worker_connections와 open files limit은 충분한가?- upstream keepalive가 Tomcat connection/thread 여유보다 과하지 않은가?
- 504는 timeout 값 문제인가, backend 처리 지연의 결과인가?
- 재시도 정책이 쓰기 요청에서 중복 처리를 만들 수 있지 않은가?