Nginx 504 게이트웨이 타임아웃 및 클라이언트 타임아웃 문제 해결
Nginx 타임아웃, 특히 두려운 504 게이트웨이 타임아웃을 마스터하여 중요한 프록시 지시문을 조정하는 방법을 배우세요. 이 가이드는 `proxy_read_timeout` 증가, 버퍼링 최적화, 오류 로그를 사용하여 Nginx와 업스트림 서버 간의 통신 실패를 진단하여 강력한 연결 처리를 수행하는 방법을 자세히 설명합니다.
Nginx 504 게이트웨이 타임아웃 및 클라이언트 타임아웃 문제 해결
Nginx 504 게이트웨이 타임아웃은 Nginx가 프록시 또는 게이트웨이 역할을 하다가 업스트림 서비스로부터 제시간에 응답을 받지 못했음을 의미합니다. 업스트림은 Node.js 앱, Gunicorn, PHP-FPM, 다른 Nginx 서비스, 내부 API 또는 로드 밸런서일 수 있습니다.
쉬운 해결책은 모든 타임아웃을 5분으로 늘리고 넘어가는 것입니다. 특히 보고서, 가져오기 또는 관리자 전용 작업의 경우 더 긴 타임아웃이 단기적으로 올바른 조치일 수 있습니다. 그러나 일반 사용자 요청이 Nginx가 현재 허용하는 것보다 더 오래 걸리는 경우, 백엔드가 왜 느린지, 요청이 비동기식이어야 하는지, 경로상의 다른 프록시에 더 짧은 타임아웃이 설정되어 있지 않은지도 물어봐야 합니다.
504 게이트웨이 타임아웃 오류 이해
504 게이트웨이 타임아웃 오류는 Nginx가 리버스 프록시 또는 게이트웨이로 작동하여 요청을 전달하는 업스트림 서버로부터 적시에 응답을 받지 못할 때 발생합니다. 간단히 말해: Nginx가 백엔드에 답변을 요청하고, 설정된 시간 동안 기다렸지만 응답이 도착하지 않아 포기했습니다.
이는 Nginx가 유효하지 않거나 조기에 종료된 업스트림 응답을 받은 502 배드 게이트웨이 및 서비스가 의도적으로 사용 불가능하거나 과부하 상태임을 의미하는 503 서비스 사용 불가와 다릅니다. 이러한 구분은 504가 대기, 시간 및 업스트림 지연 시간을 가리키기 때문에 중요합니다.
업스트림 타임아웃을 제어하는 주요 지시문
요청을 프록시할 때 Nginx는 주로 http, server 또는 location 블록 내에 있거나 특히 upstream 블록 내에 있는 몇 가지 중요한 지시문을 사용합니다. 이러한 값을 조정하는 것이 504 오류를 해결하는 주요 방법입니다.
1. proxy_connect_timeout
업스트림 서버와의 연결을 설정하기 위한 타임아웃을 설정합니다. Nginx가 이 기간 내에 연결할 수 없으면 타임아웃 오류를 반환합니다.
기본값: 60초
proxy_connect_timeout 60s;
2. proxy_send_timeout
업스트림 서버에 대한 두 번의 연속 쓰기 작업 사이의 시간에 대한 타임아웃을 설정합니다. 이는 큰 요청 본문을 보낼 때 관련됩니다.
기본값: 60초
proxy_send_timeout 60s;
3. proxy_read_timeout (504에 대한 가장 일반적인 수정)
요청 헤더가 전송된 후 업스트림 서버로부터 응답을 기다리는 타임아웃을 설정합니다. 백엔드 애플리케이션이 요청을 처리하고 응답 본문을 생성하는 데 너무 오래 걸리는 경우 이 지시문을 늘려야 합니다.
기본값: 60초
# 예: 느린 API의 읽기 타임아웃을 120초로 증가
proxy_read_timeout 120s;
애플리케이션이 기본값을 자주 초과하는 경우 이 값을 신중하게 늘리고 계속 조사하십시오. 매우 높은 값은 백엔드가 이미 비정상인 상태에서 클라이언트 연결을 열어 둘 수 있습니다.
클라이언트 측 타임아웃 처리
클라이언트 측 타임아웃은 다른 종류의 실패입니다. 브라우저, 모바일 앱, 로드 밸런서, CDN 또는 호출 서비스가 Nginx가 응답을 완료하기 전에 포기합니다. 이 경우 사용자는 브라우저 오류 또는 Nginx 앞의 계층에서 게이트웨이 오류를 볼 수 있으며, Nginx는 깔끔한 504 대신 닫힌 연결을 기록할 수 있습니다.
Nginx가 504를 기록하기 전에 클라이언트 타임아웃이 발생하는 경우 클라이언트와 Nginx 간의 연결을 살펴봐야 합니다.
1. 클라이언트 측 Keepalive
클라이언트가 연결을 조기에 종료하면 Nginx가 오류를 수신하거나 클라이언트가 데이터를 기다리다가 단순히 타임아웃될 수 있습니다.
클라이언트가 다른 프록시 또는 로드 밸런서인 경우 Nginx 및 백엔드에 대한 타임아웃 설정을 확인하십시오. 체인에서 가장 짧은 타임아웃이 일반적으로 적용됩니다. 일반적인 패턴은 다음과 같습니다: CDN이 100초 대기, 로드 밸런서가 60초 대기, Nginx가 180초 대기, 백엔드가 120초 소요. 로드 밸런서가 먼저 포기하기 때문에 사용자는 여전히 60초에 실패합니다.
2. Nginx send_timeout
이 지시문은 Nginx가 클라이언트가 데이터를 확인하거나 수신할 때까지 기다리는 시간(클라이언트에 대한 두 번의 연속 쓰기 작업 사이의 시간)을 제어합니다.
기본값: 60초
# Nginx가 응답을 보내는 동안 클라이언트가 타임아웃되는 경우 설정
send_timeout 120s;
큰 응답을 위한 버퍼링 최적화
때로는 백엔드가 응답을 시작하지만 응답이 너무 크거나, 클라이언트가 느리거나, Nginx가 예상보다 더 많이 버퍼링해야 하기 때문에 전달이 여전히 느립니다. 이는 생성된 CSV 내보내기, 앱을 통해 라우팅되는 미디어 다운로드 또는 매우 큰 JSON 페이로드를 반환하는 API에서 일반적입니다.
Nginx는 버퍼를 사용하여 업스트림에서 받은 데이터를 클라이언트로 보내기 전에 임시로 보관합니다. 응답이 매우 큰 경우 이러한 버퍼가 초과되어 복잡한 처리 또는 인지된 지연이 발생할 수 있습니다.
주요 버퍼링 지시문
이는 일반적으로 location 블록 또는 server 블록 내에 설정됩니다:
| 지시문 | 목적 |
|---|---|
proxy_buffers |
업스트림에서 응답을 읽는 데 사용되는 버퍼의 수와 크기를 설정합니다. 형식: number size; |
proxy_buffer_size |
응답 헤더를 읽는 데 사용되는 첫 번째 버퍼의 크기를 설정합니다. |
proxy_max_temp_file_size |
응답이 사용 가능한 버퍼를 초과하면 Nginx는 임시 파일에 씁니다. 이는 이러한 임시 파일의 최대 크기를 설정합니다. |
대용량/큰 응답을 위한 예제 구성:
location /api/heavy_report {
proxy_pass http://backend_app;
# 읽기 타임아웃 증가
proxy_read_timeout 180s;
# 잠재적으로 큰 응답 본문에 대한 버퍼링 조정
# 각각 최대 1MB(1024k)인 8개의 버퍼 사용
proxy_buffers 8 1024k;
proxy_buffer_size 256k;
# 버퍼가 오버플로우되는 경우 최대 500MB의 임시 파일 허용
proxy_max_temp_file_size 500m;
}
백엔드 응답이 정말로 큰 경우 앱을 통해 요청을 열어 두는 대신 객체 스토리지 또는 정적 스토리지에서 생성된 파일을 제공하는 것을 고려하십시오. 내보내기의 경우 일반적인 패턴은 작업을 대기열에 넣고 파일을 생성한 다음 사용자가 준비되었을 때 정적 URL에서 다운로드하도록 하는 것입니다.
문제 해결 단계 및 로그 분석
타임아웃을 해결하려면 지연이 발생한 위치(클라이언트 -> Nginx 또는 Nginx -> 백엔드)를 정확히 찾아내야 합니다.
1단계: Nginx 오류 로그 확인
Nginx 오류 로그는 Nginx가 백엔드를 기다리다가 타임아웃되었는지 확인하는 결정적인 소스입니다.
다음과 같은 문구가 포함된 항목을 찾으십시오:
upstream timed out (110: Connection timed out)upstream prematurely closed connection while reading response header from upstream
이러한 항목이 보이면 문제는 proxy_read_timeout 또는 백엔드의 처리 시간에 있습니다.
또한 client prematurely closed connection을 찾으십시오. 이는 일반적으로 클라이언트 또는 Nginx 앞의 프록시가 먼저 포기했음을 의미합니다. 이 경우 proxy_read_timeout만 높여도 사용자에게 도움이 되지 않습니다.
2단계: 백엔드 애플리케이션 로그 확인
Nginx가 타임아웃되면(로그에 504 표시) 즉시 업스트림 서비스(예: PHP-FPM 로그, Gunicorn 로그, Java 애플리케이션 서버 로그)의 로그를 확인하십시오. 요청이 백엔드에 도달했는지와 완료하는 데 걸린 시간을 확인해야 합니다.
- 백엔드 로그에 요청이 구성된
proxy_read_timeout보다 더 오래 걸린 것으로 표시되면 Nginx 타임아웃을 늘리십시오. - 백엔드 로그에 요청이 빠르게 완료된 것으로 표시되면 문제는 Nginx와 백엔드 간의 네트워크 지연 또는 Nginx를 향한 잘못 구성된 클라이언트 타임아웃일 수 있습니다.
3단계: X-Upstream-Response-Time 헤더 사용 (선택 사항)
자세한 진단을 위해 액세스 로그 형식에 $upstream_response_time 변수를 사용하여 업스트림이 응답하는 데 걸린 정확한 시간을 기록할 수 있습니다. 이는 백엔드의 실제 성능을 확인하는 데 도움이 됩니다.
nginx.conf에서:
log_format proxy_detailed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time $upstream_response_time';
access_log /var/log/nginx/access.log proxy_detailed;
$upstream_response_time을 분석하면 Nginx의 자체 타임아웃 설정과 관계없이 Nginx가 기다린 정확한 시간을 확인할 수 있습니다.
빠른 일회성 테스트를 위해 Nginx 호스트에서 업스트림을 직접 호출하십시오:
time curl -sS -o /dev/null -w 'status=%{http_code} total=%{time_total}\n' http://127.0.0.1:3000/slow-route
직접 업스트림 호출이 이미 느리다면 Nginx는 문제를 보고하는 것뿐입니다. 직접 호출은 빠르지만 프록시된 요청이 타임아웃되면 프록시 구성, DNS 확인, 컨테이너 네트워킹, 내부 서비스 간 TLS 또는 Nginx와 앱 사이의 다른 홉을 검사하십시오.
가장 작은 유용한 변경 적용
합리적인 프로덕션 수정은 종종 다음과 같습니다:
location /api/reports/ {
proxy_pass http://backend_app;
proxy_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 180s;
}
이렇게 하면 느린 보고서 엔드포인트에 대해서만 읽기 타임아웃이 증가합니다. 사이트의 모든 요청이 3분을 기다리게 하지는 않습니다. 로그인 경로, 체크아웃 경로, 상태 확인 또는 공개 API 엔드포인트의 경우 긴 타임아웃은 클라이언트가 복구될 가능성이 없는 요청을 더 오래 기다리게 하여 실패를 더 고통스럽게 만들 수 있습니다.
PHP-FPM의 경우 동등한 것은 FastCGI 지시문을 포함할 수 있습니다:
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 120s;
include fastcgi_params;
}
PHP, Python, Node.js, 애플리케이션 서버, 큐, 데이터베이스, CDN 및 로드 밸런서 모두 자체 타임아웃 설정이 있을 수 있음을 기억하십시오. Nginx는 백엔드의 자체 작업자 타임아웃이 요청을 종료한 후에 백엔드가 계속 작동하도록 만들 수 없습니다.
구성 변경(예: 타임아웃 증가 또는 버퍼 크기 조정)을 수행한 후에는 항상 구성 구문을 테스트하고 Nginx를 다시 로드하십시오:
sudo nginx -t
sudo systemctl reload nginx
그런 다음 동일한 요청을 반복하면서 Nginx 및 업스트림 로그를 모두 모니터링하십시오:
sudo tail -f /var/log/nginx/error.log
가장 좋은 타임아웃 수정은 변경 이유를 명확히 남깁니다: 이 경로는 합법적으로 최대 2분이 걸리고, 이 업스트림은 이제 일치하는 제한이 있으며, 느린 요청은 로그 또는 메트릭에 표시됩니다. 그보다 적은 것은 임시 패치이며, 임시 패치는 구성 검토 또는 인시던트 노트에 그렇게 표시되어야 합니다.