본문으로 건너뛰기
개발 머꼬
개발 노트Redis
hohyeon.dev22

Pub/Sub으로 보낸 알림이 조용히 사라진 이유

  • #Engineering Note
  • #Redis

문제 발생

백그라운드 작업 완료 알림을 Pub/Sub으로 보냈습니다.

PUBLISH job:done "{\"id\":123}"

대부분 잘 동작했는데, 배포로 컨슈머가 재시작되는 몇 초 동안 발행된 메시지가 통째로 사라졌습니다. 재시도도, 큐에 남는 것도 없었습니다.

원인 분석

설계된 동작입니다. Redis 문서가 전달 의미론을 분명히 적습니다 — Redis의 Pub/Sub은 at-most-once(최대 1회) 메시지 전달 의미론을 가집니다. 이름 그대로 메시지는 전달된다면 한 번 전달된다는 뜻입니다. Redis 서버가 메시지를 보낸 뒤에는 다시 보낼 가능성이 없습니다. 그리고 결정적으로 — 구독자가 (오류나 네트워크 연결 끊김 등으로) 메시지를 처리할 수 없으면 그 메시지는 영원히 사라집니다.

메시지가 어디에도 저장되지 않기 때문입니다. Pub/Sub은 키 공간과 무관하고(문서에 따르면 데이터베이스 번호와도 무관해서 db 10에 발행한 것을 db 1의 구독자가 받습니다), 발행 시점에 연결된 구독자에게만 밀어 넣습니다.

더 강한 보장이 필요할 때의 대안도 문서가 지목합니다 — 애플리케이션에 더 강한 전달 보장이 필요하다면 Redis Streams를 살펴보십시오. 스트림의 메시지는 영속되며 at-most-once와 at-least-once 전달 의미론을 모두 지원합니다.

해결 방안

  1. 유실돼도 되는 것에만 씁니다. 실시간 시세 표시, 타이핑 중 표시, 캐시 무효화 신호처럼 다음 메시지가 곧 오는 용도가 Pub/Sub의 자리입니다.

  2. 유실되면 안 되는 것은 Streams로 옮깁니다. 소비자 그룹으로 처리 상태를 추적하면 재시작 중 발행된 메시지도 이어서 받습니다.

  3. 작업 큐가 필요하면 큐를 씁니다. "완료 알림"이 아니라 "완료 처리"라면 애초에 큐(Streams, 또는 전용 브로커)가 맞습니다.

  4. 캐시 무효화에도 안전망을 둡니다. 무효화 신호를 놓치면 낡은 데이터가 남습니다 — TTL을 함께 걸어 최악의 경우에도 스스로 만료되게 합니다.

  5. 패턴 구독의 중복을 인지합니다. 문서 설명대로 채널과 패턴을 동시에 구독하면 같은 메시지를 여러 번 받을 수 있습니다 — 핸들러를 멱등하게 만듭니다.

  6. 클러스터에서는 sharded Pub/Sub을 검토합니다. 일반 Pub/Sub은 모든 노드로 전파되어 클러스터 버스를 크게 씁니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.