연결 최적화 — keepalive·버퍼·타임아웃 튜닝
Nginx와 Tomcat 사이의 연결 효율을 높이는 핵심 설정을 다룹니다. keepalive 연결 재사용, 버퍼 크기 조정, 타임아웃 3종(connect·send·read) 튜닝을 실무 기준으로 설명합니다.
연결 흐름 이해
최적화를 위해 먼저 Nginx → Tomcat 연결의 전체 흐름을 파악합니다.
클라이언트 ←→ Nginx ←→ Tomcat
[연결 수립]
1. 클라이언트 → Nginx: TCP 연결 + TLS 핸드셰이크
2. Nginx → Tomcat: TCP 연결 (proxy_connect_timeout 이내)
[요청 전달]
3. Nginx → Tomcat: 요청 헤더 + 바디 전송 (proxy_send_timeout 이내)
[응답 수신]
4. Tomcat → Nginx: 응답 헤더 + 바디 수신 (proxy_read_timeout 이내)
5. Nginx → 클라이언트: 응답 전달
keepalive — 연결 재사용
TCP 연결을 매 요청마다 새로 수립하면 Tomcat에 부하가 걸립니다. keepalive로 연결을 재사용하면 레이턴시와 CPU 사용량이 크게 줄어듭니다.
Nginx upstream keepalive 설정
upstream tomcat_backend {
server 127.0.0.1:8080;
# keepalive: Nginx가 Tomcat과 유지할 유휴 연결 수
# (동시 요청 수의 약 50% 권장)
keepalive 64;
# keepalive 연결 최대 요청 수 (이후 연결 갱신)
keepalive_requests 1000;
# keepalive 연결 유지 시간
keepalive_time 1h;
keepalive_timeout 75s;
}
server {
location / {
proxy_pass http://tomcat_backend;
# keepalive 사용 시 반드시 HTTP/1.1 + Connection "" 설정
proxy_http_version 1.1;
proxy_set_header Connection ""; # "keep-alive" 아닌 "" (빈 문자열)
}
}
중요:
proxy_http_version 1.1과proxy_set_header Connection ""을 함께 설정해야 keepalive가 동작합니다.Connection: keep-alive헤더를 Tomcat에 전달하면 오히려 문제가 생길 수 있습니다.
Tomcat HTTP 커넥터 keepalive 설정
Nginx와 Tomcat 양쪽에서 keepalive를 지원해야 합니다.
<!-- server.xml -->
<Connector port="8080" protocol="HTTP/1.1"
keepAliveTimeout="75000" <!-- Nginx keepalive_timeout과 맞춤 -->
maxKeepAliveRequests="1000" <!-- Nginx keepalive_requests와 맞춤 -->
connectionTimeout="20000"
maxThreads="200"/>
타임아웃 3종 완전 이해
location / {
proxy_pass http://tomcat_backend;
# 1. connect_timeout: Nginx → Tomcat TCP 연결 수립 대기 시간
# Tomcat이 응답 없으면 502 반환
proxy_connect_timeout 10s;
# 2. send_timeout: Nginx → Tomcat 요청 전송 중 두 패킷 사이 최대 대기 시간
# 클라이언트가 느린 업로드를 할 때 영향
proxy_send_timeout 60s;
# 3. read_timeout: Tomcat → Nginx 응답 수신 중 두 패킷 사이 최대 대기 시간
# Tomcat 처리 시간보다 길게 설정해야 함
proxy_read_timeout 60s;
}
타임아웃 설정 가이드
| 상황 | connect | send | read |
|---|---|---|---|
| 일반 API | 5~10s | 30s | 30~60s |
| 파일 업로드 | 5~10s | 300s | 60s |
| 파일 다운로드 | 5~10s | 60s | 300s |
| 장시간 처리 (배치) | 5~10s | 60s | 600s+ |
| WebSocket | 5~10s | 3600s | 3600s |
경로별 타임아웃 분리
# 일반 API
location /api/ {
proxy_pass http://tomcat_backend;
proxy_connect_timeout 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# 파일 업로드
location /api/upload {
proxy_pass http://tomcat_backend;
proxy_connect_timeout 5s;
proxy_send_timeout 300s;
proxy_read_timeout 60s;
proxy_request_buffering off; # 청크 업로드 지원
client_max_body_size 500m;
}
# 배치 작업 (시간이 오래 걸리는 API)
location /api/batch/ {
proxy_pass http://tomcat_backend;
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 600s;
}
버퍼 설정
버퍼는 Tomcat의 응답을 Nginx가 임시 저장하는 공간입니다. 올바른 버퍼 설정으로 클라이언트 속도와 무관하게 Tomcat 스레드를 빠르게 해제할 수 있습니다.
location / {
proxy_pass http://tomcat_backend;
# 버퍼링 활성화 (기본값 on)
proxy_buffering on;
# 응답 헤더용 버퍼 크기 (헤더가 크면 늘릴 것)
proxy_buffer_size 16k;
# 응답 본문용 버퍼 (개수 × 크기)
proxy_buffers 8 64k; # 512KB
# 클라이언트에 전달 중인 버퍼 최대 크기
proxy_busy_buffers_size 128k;
# 임시 파일 사용 (버퍼가 꽉 찬 경우)
proxy_temp_path /var/cache/nginx/proxy_temp;
proxy_max_temp_file_size 1024m;
proxy_temp_file_write_size 64k;
}
버퍼 크기 산정 기준
| 응답 크기 | 권장 설정 |
|---|---|
| 소형 API (< 4KB) | buffer_size 4k, buffers 4 4k |
| 일반 웹 페이지 (< 64KB) | buffer_size 16k, buffers 4 64k (기본값) |
| 대용량 JSON (< 1MB) | buffer_size 32k, buffers 8 128k |
| 파일 다운로드 | proxy_buffering off (스트리밍) |
캐시 설정 (선택적 프록시 캐시)
자주 변경되지 않는 API 응답을 Nginx에서 캐시하면 Tomcat 부하를 줄일 수 있습니다.
# nginx.conf http 블록
proxy_cache_path /var/cache/nginx/proxy_cache
levels=1:2
keys_zone=tomcat_cache:10m
max_size=1g
inactive=60m
use_temp_path=off;
# location 블록
location /api/products {
proxy_pass http://tomcat_backend;
proxy_cache tomcat_cache;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 5m; # 200 응답 5분 캐시
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating;
proxy_cache_lock on;
# 캐시 상태 헤더 추가 (디버깅용)
add_header X-Cache-Status $upstream_cache_status;
# 특정 쿠키/헤더가 있으면 캐시 우회
proxy_cache_bypass $http_authorization;
proxy_no_cache $http_authorization;
}
종합 최적화 설정 예시
upstream tomcat_backend {
server 127.0.0.1:8080;
keepalive 64;
keepalive_requests 1000;
keepalive_timeout 75s;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# 클라이언트 설정
client_max_body_size 50m;
client_body_buffer_size 128k;
client_header_buffer_size 4k;
large_client_header_buffers 4 16k;
# 기본 API 프록시
location /api/ {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 10s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
}
# 대용량 업로드
location /api/upload {
proxy_pass http://tomcat_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 500m;
proxy_request_buffering off;
proxy_connect_timeout 5s;
proxy_send_timeout 300s;
proxy_read_timeout 60s;
}
# 정적 파일
location ~* \.(css|js|png|jpg|webp|woff2)$ {
root /var/www/myapp;
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
}
성능 측정 및 검증
# ab 로드 테스트
ab -n 10000 -c 200 https://example.com/api/users
# 연결 현황 확인 (ESTABLISHED, TIME_WAIT 등)
ss -s
ss -tnp | grep nginx | wc -l
# Nginx 업스트림 상태 확인 (nginx-module-vts 또는 status 페이지 필요)
curl http://localhost/nginx_status
# Tomcat 활성 스레드 확인
curl -u admin:password http://localhost:8080/manager/status
Summary
| 최적화 항목 | 설정 | 효과 |
|---|---|---|
| keepalive | keepalive 64 + HTTP/1.1 | TCP 재연결 오버헤드 제거 |
| connect timeout | proxy_connect_timeout 10s | 장애 Tomcat 빠른 감지 |
| read timeout | proxy_read_timeout 30~60s | Tomcat 처리 시간에 맞게 |
| 버퍼링 | proxy_buffers 4 64k | Tomcat 스레드 빠른 해제 |
| 캐시 | proxy_cache_path | 반복 요청 Tomcat 부하 감소 |
| HTTP/2 | listen 443 ssl http2 | 클라이언트 다중화 이점 |