스테이지 서버의 네트워크 패킷을 분석하다가 이상한 점을 발견했습니다. 요청마다 TCP 연결이 열렸다 닫혔다를 반복하고 있었습니다.
Keep-Alive가 제대로 동작하고 있다면 한번 맺은 연결을 재사용해야 하는데, 실제로는 매 요청마다 3-way Handshake가 발생하며 불필요한 연결 비용이 계속 발생하는 상태였습니다.

패킷 분석시 매번 닫고 다시 열고 있음
Nginx 설정을 다시 살펴봤습니다. 기존 설정에서는 proxy_pass에 IP를 직접 명시하고 있었습니다.
location / {
proxy_pass <http://127.0.0.1:8083>;
}
HTTP/1.1로 Keep-Alive를 쓰려면 proxy_http_version 1.1을 설정하면 된다고 알고 있었는데, 이것만으로는 실제로 동작하지 않았습니다.
핵심은 커넥션 풀을 관리하는 upstream 블록이 없었습니다.
Nginx는 upstream을 통해 백엔드와의 연결을 풀링합니다. proxy_pass에 IP를 직접 쓰면 매 요청마다 새 연결을 맺고 끊는 HTTP/1.0 방식으로 동작합니다.
upstream 블록을 추가하고, proxy_pass가 이를 참조하도록 변경했습니다.
upstream backend_dev {
server 127.0.0.1:8083 max_fails=3 fail_timeout=30s;
keepalive 32; # 유지할 유휴 연결 수
keepalive_requests 100; # 연결당 최대 요청 수
keepalive_timeout 60s; # 유휴 연결 유지 시간
}
server {
listen 443 ssl http2;
location / {
proxy_pass http://backend_dev; # upstream 참조
proxy_http_version 1.1;
proxy_set_header Connection ""; # Keep-Alive 활성화 핵심
proxy_set_header Host $http_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_set_header Connection ""; 설정도 중요합니다. 이를 비워두지 않으면 Nginx가 upstream에 Connection: close 헤더를 전달하여 연결이 강제로 끊어집니다.
패킷 분석 결과, 변경 전후가 명확하게 달랐습니다.