← posts/b.log()

blog92@web:~$ cat posts/websocket-09-reconnection-strategy.md

NETWORK1 min read

WebSocket 완전 정복 9편 — 재연결 전략: 지수 백오프와 지터, seq 기반 상태 복구

연결은 반드시 끊긴다는 전제에서 출발해 thundering herd를 막는 지수 백오프와 full jitter, 재연결하면 안 되는 상황을 코드로 구분하는 법, 그리고 스냅샷·seq 재전송·하이브리드 세 가지 상태 복구 방식과 그에 필요한 저장소를 다룹니다.

WebSocket 완전 정복 · 2부. 중급: 프로토콜 내부와 설계 패턴 · 16편 중 9편

이전 편: 8편 — 메시지 설계

8편의 봉투에 seq를 넣어 둔 이유가 이번 편에서 드러납니다. 연결은 반드시 끊긴다는 전제에서 출발해, 수천 클라이언트가 한꺼번에 돌아오는 것을 막는 지수 백오프와 지터, 재연결하면 안 되는 경우를 코드에서 가르는 법, 그리고 끊긴 동안 놓친 이벤트를 seq로 되찾는 복구 방식을 다룹니다.

연결은 반드시 끊긴다

연결은 반드시 끊깁니다(모바일 네트워크 전환, 절전, 서버 배포). 핵심은 지수 백오프 + 지터. 서버 재시작 시 수천 클라이언트가 동시에 재접속하는 thundering herd를 막습니다.

지수 백오프와 지터

ts
class ReconnectingSocket {
  private ws?: WebSocket;
  private attempt = 0;
  private lastSeq = 0;
  private closedByUser = false;
 
  constructor(private url: string, private onEvent: (msg: any) => void) {
    this.connect();
  }
 
  private connect() {
    this.ws = new WebSocket(this.url);
 
    this.ws.onopen = () => {
      this.attempt = 0;
      // 상태 복구: 마지막 seq 이후를 요청
      this.ws!.send(JSON.stringify({ type: "resume", since: this.lastSeq }));
    };
 
    this.ws.onmessage = (e) => {
      const msg = JSON.parse(e.data);
      if (typeof msg.seq === "number") {
        if (msg.seq <= this.lastSeq) return; // 중복 무시
        this.lastSeq = msg.seq;
      }
      this.onEvent(msg);
    };
 
    this.ws.onclose = (e) => {
      if (this.closedByUser) return;
      if (e.code >= 4000 && e.code < 4100) return; // 예: 인증 실패 → 재연결 금지
      const base = Math.min(30_000, 500 * 2 ** this.attempt++);
      const delay = Math.random() * base; // full jitter
      setTimeout(() => this.connect(), delay);
    };
  }
 
  close() { this.closedByUser = true; this.ws?.close(1000); }
}

재연결 트리거와 끊긴 동안의 데이터 복구

  • 브라우저에선 online/offline, visibilitychange 이벤트 활용.
  • 끊긴 동안의 데이터 복구 방식: 스냅샷(전체 재수신), seq 재전송(빠진 것만), 하이브리드(짧은 단절은 재전송, 긴 단절은 스냅샷).
  • 재전송하려면 서버가 최근 이벤트를 보관해야 함 → Redis Streams, Kafka 등 로그형 저장소.

더 깊이

COMMENTS (…)

댓글을 불러오는 중이에요.

NEW COMMENT0 / 1000
⌘↵ 전송

blog92@web:~$ cd ..