WebSocket 하트비트로 연결 생존을 확인하고 재연결 뒤 누락·중복 메시지를 복구하려면 어떤 상태를 저장해야 하나요?
잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?
답변과 점검 포인트 펼치기답변 접기
구두 답변
정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.
TCP나 WebSocket 소켓이 로컬에서 아직 닫히지 않았다는 사실과 상대 애플리케이션이 정상 처리 중이라는 사실은 다릅니다. 반열림 연결이나 중간 경로 단절은 한동안 감지되지 않을 수 있습니다. WebSocket protocol Ping/Pong은 라이브러리가 애플리케이션 로직과 무관하게 응답할 수 있으므로, Pong만으로 애플리케이션 liveness를 증명하지 않겠습니다. 필요하면 별도의 application heartbeat를 두고 응답 시각으로 서비스 처리 가능성을 추정합니다. 재연결 뒤 누락·중복을 복구하려면 하트비트 상태만으로는 부족하고, 이벤트 ID·순서 커서·마지막 적용 위치와 서버의 보관 정책을 저장해야 합니다.
생존 감지와 재연결 폭주
하트비트 간격은 프록시·로드밸런서의 유휴 종료보다 짧고, 정상 RTT 변동보다 충분히 길게 정합니다. 한 번의 pong 누락으로 즉시 장애 처리하면 일시적인 지연에도 연결이 끊기고 재연결 폭주가 발생하므로, 연속 실패 횟수나 deadline을 둡니다. WebSocket ping/pong은 전송 경로와 소켓 응답을 확인하는 데 유용하지만, 서버 애플리케이션이 실제로 이벤트를 처리하고 DB를 커밋했다는 뜻은 아닙니다. 애플리케이션 로직의 생존을 확인하려면 별도의 응용 메시지에 응답하도록 해야 하며, 그 heartbeat RTT와 실제 요청 처리 지연도 별도로 기록합니다.
재연결은 지수 백오프와 무작위 지연, 최대 간격, 인증 갱신, 서버별 동시 재접속 상한을 적용합니다. 클라이언트가 다시 연결할 때 세션 ID와 마지막으로 적용·확인한 커서를 보냅니다. 서버가 이벤트 로그를 보관하고 있으면 그 다음 이벤트부터 재전달하고, 이미 적용한 이벤트를 ACK 유실로 다시 받는 경우를 정상 경로로 취급합니다.
누락·중복·보관 만료
중요한 메시지에 스트림별 커서와 이벤트 ID를 둡니다. 다음 예는 해당 소비자에게 전달할 이벤트에 빈 번호 없이 증가하는 순서 번호를 부여한다는 전제입니다. 필터링된 전역 번호라면 숫자 차이만으로 누락을 단정할 수 없습니다. 클라이언트의 현재 기대 번호를 n, 받은 이벤트 번호를 m이라 하겠습니다. m<n이면 이미 적용한 이벤트의 중복이므로 버리고, m=n이면 적용한 뒤 기대 번호를 늘리며, m>n이면 그 사이 이벤트가 빠진 갭이므로 재전송이나 스냅샷을 요청합니다. 로컬 반영과 커서 저장을 먼저 원자적으로 끝낸 뒤 ACK를 보내야 합니다. ACK 기준으로 서버가 이후 이벤트를 재생하는 계약과 클라이언트의 로컬 저장 원자성은 별개의 보장이라서, 이를 하나로 가정하지 않겠습니다. 이벤트가 이미 외부 상태를 바꾼 경우에도 이벤트 ID·버전으로 멱등 처리합니다.
오래 오프라인이라 이벤트 보관 기간이 지났다면 서버는 임의의 과거 이벤트를 보내지 말고 최신 스냅샷과 그 스냅샷 기준 커서를 제공해야 합니다. 여러 기기가 같은 계정으로 연결되면 커서를 기기별로 둘지 사용자 전역으로 둘지 정하고, 한 기기의 ACK가 다른 기기의 미수신 이벤트를 삭제하지 않게 합니다. 테스트는 적용 직후 ACK 유실, 반열림 연결, 서버 재시작, 커서 만료, 중복·역순 이벤트, 동시 재연결을 재현합니다. 성공 기준은 재연결 성공률만이 아니라 누락 없이 복구되고 중복 효과가 남지 않는 것입니다.
하트비트 timeout은 연결을 닫을 판단이지, 미확인 애플리케이션 이벤트를 삭제할 판단이 아닙니다. 클라이언트는 마지막으로 로컬 상태에 적용한 커서와 서버가 확인한 커서를 구분해 보내고, 서버는 재전송 범위를 이 정보로 계산합니다. 이벤트 로그가 이미 정리됐다면 스냅샷의 기준 버전과 이후 이벤트를 함께 제공해야 중간 상태를 건너뛰지 않습니다. 재연결 직후 인증·동기화 요청도 서버가 처리할 수 있는 동시성으로 제한하며, ACK를 받기 전에 로컬 적용을 확정할지의 순서를 명시하겠습니다.
서버가 커서를 확인했다고 해서 클라이언트가 해당 이벤트를 실제 화면과 로컬 저장소에 적용했다는 뜻은 아닙니다. ACK의 의미를 수신·저장·화면 반영 중 어디까지로 정할지 명시하고, 재연결 요청은 그 기준에 맞는 마지막 커서를 사용합니다. 외부 부수 효과가 있는 이벤트는 연결 계층이 아니라 도메인 ID와 멱등 처리로 중복을 막겠습니다.
득점 포인트
이해가 드러나는 지점을 확인해 보세요.
- 소켓 생존·heartbeat 응답·실제 애플리케이션 처리를 서로 구분한다.
- heartbeat deadline·연속 실패·백오프·무작위 지연으로 재접속 폭주를 제한한다.
- 이벤트 ID·커서·스냅샷·보관 만료를 누락 복구에 연결한다.
- ACK 유실 뒤 재전달과 멱등 적용을 정상 경로로 설계한다.
감점 포인트
놓치기 쉬운 조건과 오해를 짚어 보세요.
- 연결이 열려 있으면 상대 애플리케이션과 DB가 정상이라고 말한다.
- 재연결만 하면 서버가 누락 메시지를 자동으로 복구한다고 가정한다.
- ACK 유실 뒤 같은 이벤트가 절대 다시 오지 않거나 중복 효과가 없다고 말한다.
더 파고들 거리
하나 더 질문하며 이해의 범위를 넓혀 보세요.
- 오래 오프라인인 client가 이벤트 보관 범위를 벗어났습니다. snapshot과 증분 재생을 어떤 기준으로 전환하나요?
- heartbeat는 정상인데 실제 요청만 느릴 때 전송·처리·DB 중 어느 구간을 측정할까요?
- 여러 기기의 커서와 세션 소유권을 사용자 전역 상태와 어떻게 나눌까요?
득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.
원리부터 공부하고 싶다면
답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.