문제
요청이 502 Bad Gateway를 반환하고 nginx 에러 로그에 no live upstreams while connecting to upstream이 찍혀 있습니다. 이건 백엔드 하나가 연결에 실패한 것과 다릅니다. nginx가 업스트림 그룹 전체를 보고 그 안의 모든 서버가 그 순간 요청을 받을 자격이 없다고 판단해 — 프록시할 대상이 없어 — 연결을 시도하지도 않고 502를 냈다는 뜻입니다. 먼저 답할 질문은, nginx가 당신의 서버들을 축출한 것인지(수동 헬스체크가 전부 쳐냄) 아니면 설정이 애초에 라우팅할 대상을 안 남긴 것인지입니다. 이 둘은 완전히 다른 버그이기 때문입니다.
증상
- 클라이언트는 밋밋한
502 Bad Gateway를 보고, nginx 에러 로그에no live upstreams while connecting to upstream이 뜹니다. curl로 직접 때리면 백엔드는 멀쩡히 응답합니다 — 문제는 앱이 아니라 nginx의 라우팅 판정입니다.- 백엔드가 여럿이면 간헐적이고 부하 스파이크와 맞물립니다 — 몇 초 튀었다가 저절로 풀립니다.
- 백엔드가 하나면 설정 키워드(
down·backup·max_conns)나 DNS/resolver 실패에 묶여 있고, 앱을 아무리 재시작해도 바뀌지 않습니다.
이 에러의 실제 의미
nginx는 upstream 블록의 각 서버에 대한 판정을 계속 유지합니다. 서버를 둘 이상 나열하면 수동(passive) 헬스체크를 돌립니다 — 실제 프록시된 요청을 지켜보다가, 한 서버가 fail_timeout 안에 max_fails회 실패하면 사용 불가로 표시하고 fail_timeout이 만료될 때까지 우회한 뒤 조심스럽게 다시 시도합니다. 기본값이 공격적입니다 — max_fails=1, fail_timeout=10s — 그래서 단 한 번의 실패로도 서버가 10초간 벤치됩니다.
no live upstreams는 그룹의 모든 서버가 동시에 벤치됐을 때 nginx가 남기는 로그입니다. 자격 있는 피어가 하나도 안 남아 연결을 시도조차 못 하고 502를 냅니다. 이게 미스터리처럼 보이는 이유가 여기 있습니다 — 당신이 백엔드에 curl을 날릴 즈음엔 fail_timeout이 지나 다 “멀쩡”하지만, 그 창 동안엔 나쁜 순간 하나가 풀 전체를 쓸어버린 것입니다.
부하 중 이게 연쇄되는 방식이 사람들이 놓치는 지점입니다. 트래픽 스파이크가 한 백엔드를 max_fails를 넘길 만큼 느리게 만들고, nginx가 그걸 벤치하면서 그 몫을 생존자에게 밀어넣고, 늘어난 부하가 다음 서버를 넘어뜨리고 — 1~2초 안에 모든 서버가 걸려 그룹 전체가 fail_timeout 동안 죽습니다. 실제로는 아무도 크래시하지 않았는데도요. 지나치게 예민한 기본값으로 스스로 만든 장애입니다.
단독 서버 케이스: max_fails가 아니다
사람을 엉뚱한 길로 보내는 함정이 여기 있습니다. 업스트림 블록에 서버가 정확히 하나면 max_fails·fail_timeout 튜닝은 아무 것도 안 합니다 — nginx가 무시하기 때문입니다. 업스트림 모듈 문서에서: “그룹에 서버가 하나뿐이면 max_fails, fail_timeout, slow_start 파라미터는 무시되며, 그런 서버는 절대 사용 불가로 간주되지 않는다.”
즉 단독 백엔드는 수동 헬스체크로 축출되지 않습니다. 서버가 하나인데 no live upstreams가 뜬다면 원인은 다른 데 있고, 거의 항상 이 중 하나입니다.
- 서버가
down으로 표시됨.server줄에 남은down(또는 그걸 붙인 설정 템플릿)이 있으면 nginx는 영구 사용 불가로 봅니다.down서버 1개 = 살아 있는 서버 0개. max_conns포화. 서버의 동시 연결 수에 상한을 걸었고 그게 다 찼다면, nginx는 새 연결을 열 슬롯이 없어 그 서버를 not live로 셉니다.- 전부
backup. 모든 항목이backup인데 primary가 없으면 서비스할 살아 있는 primary가 없습니다 — backup은 primary가 죽을 때만 활성화되는데, 그 primary가 없는 것입니다. resolver/변수 업스트림 해석 실패. 업스트림 주소가 요청 시점에 해석되는 변수인데 DNS 조회가 실패하면, nginx는 연결할 주소가 없어 no live upstream으로 보고합니다.
각각은 헬스체크 튜닝 문제가 아니라 설정·DNS 문제입니다. 여기서 max_fails=3을 만지는 건 아무 것도 못 고칩니다.
DechoNet으로 진단하기
- HTTP 점검은 바깥 세계가 실제로 무엇을 받는지 — 최종 상태가 nginx발
502인지 — 확인하고, 실패하는 경로와 되는 경로를 비교하게 해줍니다. 502가 간헐적이면 반복 점검으로 부하와 상관 있는지(연쇄)인지 상시 발생인지(설정 함정) 볼 수 있습니다. nginx 에러 로그의 정확한 문구와 짝지어 보세요 — 그게 진짜 진단 열쇠입니다.
해결 체크리스트
- 정확한 로그 문구를 먼저 읽으세요.
no live upstreams(그룹 전체 사용 불가)는connect() failed·upstream timed out(한 번의 시도 실패)와 다른 버그입니다. 엉뚱한 걸 고치지 마세요. -
upstream블록의 서버 개수를 세세요. 하나 →max_fails가 아닙니다.down·backup·max_conns·resolver 실패를 확인. 여럿 → 수동 헬스체크 축출을 의심. - 다중 서버 연쇄라면 예민한 기본값을 완화하세요 —
max_fails(예: 3)와/또는fail_timeout을 올려 한 번 느린 순간이 멀쩡한 서버를 벤치하지 않게 하고, 백엔드가 느렸던 근본 원인(포화·타임아웃·GC 멈춤)을 고치세요. - 설정에서 남은
down하나, 그리고 모든 항목이backup이고 primary가 없는 블록을 grep하세요. 남은down은 제거하고, 그룹에 실제 primary를 주세요. - 업스트림이 변수+
resolver를 쓴다면 resolver가 도달 가능한지, 이름이 해석되는지 확인하세요 — 여기서의 DNS 실패가 “no live upstreams”로 읽힙니다. - HTTP 점검을 다시 돌려 해당 경로가 더 이상 502를 반환하지 않는지 확인하세요.
언제 에스컬레이션할까
- 502가 트래픽 스파이크를 따라
fail_timeout안에 풀린다면, 진짜 문제는 nginx가 아니라 업스트림 용량·지연입니다 —max_fails만 넓히지 말고 포화·느린 쿼리·커넥션 풀 한도·백엔드 타임아웃을 파세요. - 관리형 로드밸런서나 인그레스 컨트롤러 뒤에서 nginx를 돌린다면, 자체 임계값을 가진 헬스체크 계층이 하나 더 있을 수 있습니다 — 한 계층엔 “정상”인 백엔드가 다른 계층엔 벤치돼 있을 수 있습니다.
- 백엔드 하나가 응답 헤더가 nginx 버퍼를 넘쳐 502가 나는 밀접한 케이스는 upstream sent too big header (nginx 502)를, 502 일반 결정 트리는 502 Bad Gateway 체크리스트를 보세요.
내 도메인에서 바로 확인
무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.