페일오버로 DNS를 바꿨는데 옛 백엔드로 간다면, “DNS 변경 ≠ 연결 전환”이다
레코드를 새 IP로 바꿔도, 이미 맺힌 연결과 캐시된 조회는 그대로 옛 백엔드를 가리킨다. 페일오버가 안 넘어가는 진짜 이유는 대개 DNS 전파가 아니라 연결과 캐시다.
1) TTL이 길다
레코드 TTL이 3600s면 리졸버와 클라이언트가 옛 IP를 그만큼 캐시한다. 페일오버 대상 레코드는 사고 전에 미리 TTL을 30~60s로 낮춰 둬야 전환이 빠르다. 사고 난 뒤 낮추면 이미 늦다.
dig +noall +answer <name> # 남은 TTL 확인
2) 연결이 재사용된다 (가장 흔한 진짜 원인)
이미 맺힌 TCP 연결은 DNS와 무관하게 유지된다. HTTP keep-alive와 커넥션 풀은 옛 소켓을 계속 쓰고, 특히 HTTP/2는 단일 롱리브드 연결이라 오래 붙어 있다. 전환하려면 옛 연결을 끊어야 한다 — 풀 드레인, 클라이언트 재시작, 또는 LB에서 옛 대상 연결 종료.
ss -tnp | grep <old-ip> # 실제로 아직 옛 목적지에 붙어 있는 연결
3) 앱이 DNS를 캐시한다
런타임 자체가 조회 결과를 캐시한다. JVM은 networkaddress.cache.ttl(옛 기본값은 사실상 영구)로 성공한 조회를 프로세스 수명 내내 잡아 둔다. 앱이 재조회를 안 하면 재시작 전까지 옛 IP를 쓴다.
정리
TTL 사전 하향 → 옛 연결 강제 종료(드레인/재시작) → 앱 DNS 캐시 TTL. “DNS가 전파됐는지”를 기다리기보다 옛 연결을 어떻게 끊을지가 페일오버 설계의 핵심이다.
빠른 진단 체크리스트
- DNS 변경이 곧 연결 전환은 아님을 전제한다
- 레코드 TTL을 사고 전에 미리 30~60s로 낮춰 둔다
dig +noall +answer로 남은 TTL을 확인한다- keep-alive·커넥션 풀이 옛 소켓을 재사용하는지 본다
- HTTP/2는 단일 롱리브드 연결이라 특히 오래 붙어 있다
ss -tnp로 아직 옛 IP에 붙은 연결을 확인한다- 전환하려면 풀 드레인·재시작으로 옛 연결을 끊는다
- JVM 등 앱 DNS 캐시(networkaddress.cache.ttl)를 조정한다