10. 알림 시스템 설계 본문
1단계: 문제 이해 및 설계 범위 확정
- 푸시 알림, SMS, 이메일 등 다양한 채널을 모두 지원해야 한다.
- 실시간성을 유지하되 피크 시에는 약간의 지연을 허용하는 연성 실시간(soft real‑time) 시스템이어야 한다.
- 사용자가 각 채널별 알림 설정을 켜고 끌 수 있도록 옵션을 제공해야 한다.
- 하루 평균 1,000만 건의 푸시, 100만 건의 SMS, 500만 건의 이메일 처리량을 목표로 삼아야 한다.
2단계: 개략적 설계안 제시
2.1 알림 유형별 전송 경로
- iOS 푸시: 서비스 → APNS → iOS 단말 토큰에 전달한다. (모바일.. 해볼일이 있으려나..)
- Android 푸시: FCM(Firebase Cloud Messaging)을 통해 Android 단말에 전달한다.
- SMS: 통신사(SKT, KT, LGU+)의 SMS 게이트웨이를 경유해 전송한다. (rpm은.. 어디꺼 쓰더라...)
- 이메일: SendGrid, Mailchimp 또는 자체 SMTP 서버를 활용해 발송한다. (rpm은 SES 붙였었는데잉...)
2.2 연락처 정보 저장
- 사용자 계정에 모바일 푸시 토큰, 전화번호, 이메일 주소를 저장한다.
- 자주 참조되는 정보를 Redis 같은 캐시에 보관한다.
2.3 전송 흐름
- 서비스에서 Notification API로 알림 요청을 전송한다.
- Notification 서버가 페이로드를 생성한다.
- 알림 서버 : 전송 API 제공 / 알림 검증 / DB, cache 조회 / MQ로 보내기
- 캐시/DB : 정보 가져오겠죠? 캐시는 좀 더 자주 쓰이는거 가져오겠죠?
- 채널별 메시지 큐(FIFO)에 페이로드를 발행한다.
- 각 큐의 작업 서버가 메시지를 꺼내 제3자 API(APNS/FCM/SMS/이메일)를 호출한다.
Notification 서버, DB, 캐시, 큐, 작업 서버를 모두 수평 확장해 SPOF를 제거 해야 한다!
3단계: 상세 설계
3.1 안정성
데이터 손실 방지 및 재시도
- 모든 알림 요청을 DB에 기록해 소실을 방지한다.
- 전송 실패 시 재시도 전용 큐에 넣고, 재시도 횟수를 관리하며 반복 처리한다.
- 이벤트 ID를 이용한 Bloom 필터와 DB 조회로 중복 전송을 방지한다.... 하지만!
더보기
1. 정확히 한 번 전송의 불가능성
Two Generals 문제
- 분산 시스템의 불완전한 통신 특성을 보여 주는 Two Generals’ Problem에 따르면, 메시지 손실 또는 인지 여부의 불확실성 때문에 단 한 번만, 정확히 한 번 메시지를 전달했다는 상호 확신을 가질 수 없다.
- 이 사고 실험은 “마지막 메시지가 성공적으로 도달했을 때 이를 알릴 방법이 없으면 합의가 불가능하다”는 역설을 증명하며, exactly‑once 보장 자체가 불가능함을 보인다.
2. 실무에서의 중복 방지 대체 기법
At‑Least‑Once + Idempotency
- 대부분 시스템은 at‑least‑once 전송을 채택하고, 중복 수신 시 영향을 무효화하는 멱등성(idempotent) 처리를 병행한다.
- 멱등성 처리: “같은 메시지가 여러 번 적용되어도 최종 상태가 한 번처럼 유지”되도록 설계하는 방식이다.
Deduplication (근사적 중복 제거)
- Bloom 필터 → DB 조회 순으로 초기 필터링하여 중복 메시지일 가능성을 빠르게 배제하고, 이후 DB에서 확정적으로 확인하는 2단계 검사 방식을 적용한다.
- 이 방식은 “100% 확실한 제거”가 아니라, 확률적 필터+정확 검증으로 중복 전송을 극히 낮추는 근사 해법이다.
3. 재시도 메커니즘 및 한계
재시도 큐(Re‑try Queue)
- 전송 실패 시 전용 재시도 큐에 쌓아두고, 재시도 횟수와 지연 정책을 관리하며 반복 전송을 시도한다.
- 그러나 네트워크 단절, 서비스 장애, 레이스 컨디션 등 예외 상황이 복합될 경우, 동일 메시지 재전송 가능성을 완전히 배제할 수 없다.
Exactly‑Once vs. Exactly‑Once Processing
- “Exactly‑once delivery”는 메시지 전송 횟수를, “Exactly‑once processing”은 부작용(side‑effects)을 한 번만 발생시키는 것을 의미
- 실무에서는 부작용 제어를 통해 중복 영향만 제거하고, 순수 전송 횟수 자체는 at‑least‑once로 남겨두는 것이 일반적이다.
결론
- 분산 시스템에서 “100% 중복 전송 방지(Exactly‑once delivery)”는 이론적으로 불가능하다.
- 대신 at‑least‑once + idempotent 또는 Bloom 필터+DB 조회 같은 다단계 중복 검사, 그리고 재시도 큐로 실패를 처리하는 근사적 설계로 실용적 신뢰성을 확보해야 한다.
3.2 추가 컴포넌트
사용자별 설정 및 속도 제한
- 채널·유형별 알림 설정 테이블로 전송 전 필터링을 수행한다.
- Rate Limiting을 적용해 사용자 및 시스템 전체의 전송 속도를 제한한다.
모니터링 및 오토스케일링
- 각 큐의 길이를 모니터링 지표로 삼아 작업 서버 수를 동적으로 조정한다.
- 재시도 큐 오류 누적 시 운영팀에 알림을 발송한다.
4. 완성
'ETC' 카테고리의 다른 글
9. 웹 크롤러 설계 (0) | 2025.04.22 |
---|---|
Closure Table을 이용한 File Authority 적용기 (0) | 2025.03.17 |
RDBMS 에서 tree structure 다루기 (0) | 2025.03.17 |
[Java] StringBuilder 주요 메소드 (0) | 2025.01.21 |
Cursor AI 사용기 (9) | 2024.11.07 |
Comments