채팅 재접속, 마지막 메시지 ID만 넘기면 끝일까?
채팅 클라이언트가 마지막 메시지 ID로 이어 받는 방식이 깨지는 경우를 Python WebSocket 서버와 Redis 8.10으로 재현합니다. 채우는 동안 도착한 메시지의 빠짐과 중복, MAXLEN으로 잘린 ID에 resume ok를 보내며 340건을 건너뛰는 현상, XADD IDMP로 막는 재전송 중복을 봅니다.
@Hong2026-10-14조회 117

채팅 클라이언트가 마지막 메시지 ID로 이어 받는 방식이 깨지는 경우를 Python WebSocket 서버와 Redis 8.10으로 재현합니다. 채우는 동안 도착한 메시지의 빠짐과 중복, MAXLEN으로 잘린 ID에 resume ok를 보내며 340건을 건너뛰는 현상, XADD IDMP로 막는 재전송 중복을 봅니다.

WebSocket 연결 하나는 서버에서 파일 디스크립터 하나와 메모리를 씁니다. Docker 컨테이너에서 Python websockets 서버의 nofile 한도를 1024로 낮춰 새 접속이 타임아웃으로 막히는 모습을 보고, 한도를 올린 뒤 연결을 1만 개까지 늘려 연결당 메모리(압축을 켠 기본값에서 약 57KiB)와 OOMKilled 지점을 잽니다.
WebSocket 연결은 처음 붙은 서버에 계속 머물기 때문에, 채팅 서버를 두 대로 늘리면 다른 서버에 붙은 사용자에게는 메시지가 가지 않습니다. Python WebSocket 서버 두 대와 NGINX, Redis 8.10으로 이 문제를 재현하고, Pub/Sub로 서버 간에 전달할 때 구독이 끊긴 사이 메시지가 사라지는 과정과 Streams로 바꿔 놓친 메시지를 다시 채우는 방법을 확인합니다.