웹 개발
WebSocket이 끊긴 뒤 재연결 폭주를 막은 백오프 설계
개발 환경에서는 잘 보이지 않던 재연결 폭주를 재현하고 지수 백오프와 상한을 적용한 과정입니다
연결이 끊겼는데 서버가 더 바빠졌다
실시간 알림 화면을 테스트하다가 노트북 네트워크를 잠깐 끊었습니다. 화면은 다시 연결됐지만 서버 로그에는 같은 클라이언트의 접속 시도가 초당 여러 번 찍혔습니다. 원인은 실패할수록 즉시 다시 연결하는 코드였습니다.
재현 조건부터 작게 만들기
개발자 도구에서 Offline을 켰다가 10초 뒤 끄고, 클라이언트와 서버 양쪽에 연결 시각과 시도 횟수를 남겼습니다. 정상 연결, 서버가 닫은 연결, 인증 실패를 같은 실패로 취급하면 안 됐습니다. 인증 실패는 재시도해도 해결되지 않으므로 별도 상태로 멈췄습니다.
백오프에 상한과 지터를 넣기
const MAX_DELAY = 30_000;
let attempt = 0;
function retryDelay() {
const base = Math.min(1000 * 2 ** attempt, MAX_DELAY);
attempt += 1;
return Math.round(base * (0.8 + Math.random() * 0.4));
}
function scheduleReconnect() {
window.setTimeout(connect, retryDelay());
}
function onOpen() { attempt = 0; }
지터는 여러 탭이 동시에 끊겼을 때 같은 밀리초에 몰리지 않게 합니다. 성공했을 때만 횟수를 0으로 돌리고, 화면을 닫을 때 타이머와 소켓을 취소했습니다.
확인 목록
- 인증 실패와 네트워크 실패를 구분했는가
- 재시도 간격에 최대값이 있는가
- 여러 클라이언트가 동시에 몰리지 않는가
- unmount 뒤 타이머가 남지 않는가
마지막에 남은 판단
재연결은 많이 하는 기능보다 실패했을 때 조용히 기다리는 기능에 가깝습니다. 이제 소켓 코드를 작성할 때 대기 상한과 종료 시 정리 여부를 먼저 확인합니다.