idea·blog

SERVER ERROR CLINIC

504 Gateway Timeout

프록시가 상위 서버에서 정해진 시간 안에 필요한 응답을 받지 못했습니다. 연결 단계인지 응답 대기 단계인지는 로그의 시간 항목으로 나눠야 합니다.

이 도구는 여러분의 서버에 접속하지 않습니다. 답한 내용만으로 확인할 순서를 정해주는 도구이며, 실제 로그를 대신하지 않습니다.

  1. 브라우저요청을 보낸 곳
  2. 인터넷이름 찾기·연결
  3. 프록시Nginx·Caddy
  4. Node·Spring·Django
  5. DB·외부 API여기가 의심됩니다

어느 로그를 볼까 프록시 로그에서 연결·응답 중 어느 제한시간에 걸렸는지 보고, 요청이 앱에 도달했다면 앱과 DB·외부 API의 처리 시간을 확인합니다.

원인 후보 3

오류가 뜨기까지 얼마나 걸렸나요?

걸린 시간은 어느 설정의 제한시간에 걸렸는지 알려주는 지문입니다.

가장 먼저 확인할 것

요청 하나가 원래 오래 걸린다

느린 데이터베이스 조회나 외부 API 호출이 응답을 붙잡고 있습니다. 앱은 멈춘 게 아니라 기다리는 중입니다.

다른 후보가 하나씩 제외되면서 남은 원인입니다.

앱이 첫 바이트를 내놓기까지 실제로 몇 초 걸리는지 잽니다.

curl -o /dev/null -s -w '전체 %{time_total}s / 첫 바이트 %{time_starttransfer}s\n' http://127.0.0.1:3000/

그다음 느린 쿼리부터 찾습니다. 앱 코드를 고치기 전에 어떤 요청이 몇 초 걸리는지 기록해 두면 범인이 금방 드러납니다.

캐시로 느린 조회를 줄이는 법

아니라면 다음

프록시가 기다려주는 시간이 너무 짧다

앱은 정상적으로 끝냈는데 프록시가 먼저 포기했습니다. 오래 걸리는 작업(업로드·리포트 생성)에서 흔합니다.

프록시가 몇 초까지 기다리도록 설정돼 있는지 봅니다.

grep -rn 'proxy_read_timeout\|timeouts' /etc/nginx /etc/caddy 2>/dev/null

그다음 정확히 60초에 끊겼다면 Nginx의 proxy_read_timeout 기본값(60초)일 가능성이 큽니다. 다만 시간을 늘리는 건 임시방편이고, 응답을 빠르게 만들거나 작업을 백그라운드로 빼는 쪽이 정답입니다.

아니라면 다음

커넥션 풀이 다 찼다

데이터베이스에 연결할 자리가 없어 요청들이 순서를 기다립니다. 평소엔 멀쩡하다가 몰리는 순간 한꺼번에 느려집니다.

데이터베이스 쪽 연결이 몇 개나 붙잡혀 있는지 봅니다.

SELECT count(*), state FROM pg_stat_activity GROUP BY state;

그다음 풀 크기를 키우기 전에 연결을 오래 붙잡는 쿼리를 찾습니다. 반납이 늦는 게 진짜 원인일 때가 많습니다.

실험을 마쳤다면