알림 시스템
설계 완전 분석
푸시 알림, 이메일, SMS, 인앱 알림 — 수억 건의 알림을 지연 없이, 빠짐없이, 중복 없이 전달하는 시스템은 어떻게 설계될까? 채널별 아키텍처부터 우선순위 큐, 멱등성, 사용자 설정 관리, 장애 대응까지 실무 수준으로 파고든다.
알림 시스템이란 무엇인가?
알림 시스템(Notification System)은 다양한 채널을 통해 사용자에게 정보를 전달하는 인프라다. 주문 완료, 친구 요청, 보안 경고, 마케팅 메시지 등 현대 서비스에서 발생하는 모든 알림을 처리한다. 단순한 문자 전송처럼 보이지만, 수억 명의 사용자에게 수십억 건의 알림을 신뢰성 있게, 지연 없이, 중복 없이 전달하는 것은 복잡한 분산 시스템 문제다.
알림 수 (추정)
(Push / Email / SMS / In-App)
목표 전달 지연
알림 시스템은 세 가지 핵심 원칙을 동시에 만족해야 한다. At-Least-Once Delivery(최소 한 번 전달, 유실 방지), 중복 제거(같은 알림이 여러 번 도착하지 않음), 순서 보장(인과 관계가 있는 알림의 순서 유지)이 그것이다. CAP 정리처럼 이 세 가지를 동시에 완벽히 달성하기는 어려우므로, 서비스 특성에 맞게 트레이드오프를 결정해야 한다.
트랜잭션 알림
주문 완료, 결제 성공, 비밀번호 변경 등 사용자 행동에 즉각 반응하는 알림. 신뢰성과 속도가 최우선.
마케팅 알림
프로모션, 재참여 유도, 이벤트 안내 등 대량 발송 알림. 정확한 타겟팅과 전달률 측정이 핵심.
시스템 알림
서비스 장애, 보안 이상 감지, SLA 위반 경고 등 운영 관련 알림. 지연이 절대 허용되지 않음.
소셜 알림
좋아요, 댓글, 팔로우 등 사용자 간 인터랙션 알림. 높은 발생 빈도를 효율적으로 집계해야 함.
요구사항 분석
기능 요구사항
시스템은 Push 알림(iOS/Android), 이메일, SMS, 인앱 알림 채널을 지원해야 한다. 알림은 즉시(Real-time)와 예약(Scheduled) 두 가지 발송 방식을 모두 지원한다. 사용자는 채널별로 수신 동의 여부와 수신 시간대(방해 금지)를 설정할 수 있어야 한다.
비기능 요구사항
| 항목 | 목표 | 비고 |
|---|---|---|
| 처리량 | 초당 100만 건 알림 생성, 전달 | 대형 마케팅 발송 시 피크 트래픽 고려 |
| 지연 | Critical: < 1초 / 일반: < 10초 / 마케팅: < 5분 | 알림 유형별 SLA를 다르게 설정 |
| 신뢰성 | At-Least-Once Delivery, 유실률 0%에 수렴 | 전달 실패 시 재시도 필수 |
| 중복 방지 | 동일 알림이 2회 이상 전달되지 않아야 함 | 재시도 시에도 멱등성 보장 |
| 가용성 | 99.9% 이상 | 외부 서비스(APNs, FCM) 장애에도 큐로 버퍼링 |
| 확장성 | 수평 확장으로 트래픽 대응 | 상태 없는(Stateless) 워커 설계 |
💡 규모 추정: DAU 1억 명, 사용자당 하루 평균 30건 알림 수신 → 하루 30억 건 → 초당 약 35,000 건(평균). 마케팅 대량 발송(5천만 명 동시)은 순간 초당 수십만 건까지 치솟을 수 있다. 이 피크 트래픽을 메시지 큐로 버퍼링하는 것이 아키텍처의 핵심이다.
알림 채널 4종 — 특성과 제약
채널마다 기술 스택, 전달 보장 수준, 사용자 경험이 완전히 다르다. 각 채널의 특성을 이해해야 채널별 워커를 올바르게 설계할 수 있다.
iOS는 Apple Push Notification service(APNs), Android는 Firebase Cloud Messaging(FCM)을 통해 전달된다. 서버가 직접 디바이스에 전달하지 않고 반드시 제조사의 게이트웨이를 경유해야 한다.
앱이 설치되어 있고 사용자가 권한을 허용한 경우에만 전달된다. APNs는 최근 전달된 1개의 알림만 보관하므로(Coalescing), 디바이스가 오프라인인 동안 여러 알림이 발송되면 마지막 것만 도달한다.
전달 신뢰성이 높고 긴 내용을 전달하기 적합하다. 마케팅, 영수증, 상세 공지 등에 사용된다. SendGrid, AWS SES, Mailgun 같은 이메일 서비스 제공자(ESP)를 통해 전송하는 것이 표준이다.
스팸 필터링, 도메인 평판(IP Reputation), SPF/DKIM/DMARC 설정이 전달률에 결정적 영향을 미친다. 대량 발송은 발신 IP 워밍업(Warming Up)이 필요하다.
앱 설치나 인터넷 연결이 없어도 전달된다. OTP, 보안 인증, 긴급 알림에 사용된다. Twilio, AWS SNS 등의 SMS 게이트웨이를 통해 전 세계 통신사 네트워크로 전달된다.
건당 비용이 발생하므로 대량 발송에 비용 최적화가 중요하다. 국가별로 규제가 상이하고, 일부 국가에서는 발신 번호 등록이 필수다. 160자 제한(영문 기준)이 있다.
앱이나 웹사이트를 사용 중인 사용자에게 실시간으로 표시되는 알림이다. 알림 벨 아이콘의 숫자 뱃지, 토스트 메시지, 인앱 피드 등이 이에 해당한다.
WebSocket을 통한 양방향 통신 또는 SSE(Server-Sent Events)로 실시간 푸시를 구현한다. 외부 서비스에 의존하지 않으므로 제어권이 온전히 서비스에 있다. 오프라인 사용자에게는 읽지 않은 알림으로 DB에 보관되어 다음 접속 시 표시된다.
전체 시스템 아키텍처
알림 시스템은 이벤트를 수신하는 Notification Service, 처리를 분배하는 Message Queue, 채널별로 실제 전송을 담당하는 Channel Worker 세 계층으로 구성된다.
알림 생성 — 이벤트 드리븐 설계
알림은 각 서비스에서 직접 전송 로직을 실행하는 것이 아니라, 이벤트를 발행하고 Notification Service가 이를 구독해 처리하는 이벤트 드리븐 방식이 권장된다. 서비스 간 결합도를 낮추고 알림 채널 추가 시 발신 서비스를 수정할 필요가 없다.
Notification API 처리 흐름
메시지 큐와 워커 — 비동기 파이프라인
Notification API는 이벤트를 수신하고 검증한 뒤 즉시 큐에 적재하고 응답을 반환한다. 실제 전송은 큐를 구독하는 Channel Worker가 비동기로 처리한다. 이 분리가 시스템 탄력성(Resilience)의 핵심이다 — 외부 서비스(FCM, SendGrid)가 느려지거나 다운되어도 API는 영향을 받지 않고, 큐가 버퍼 역할을 한다.
채널별 큐를 분리해야 하는 이유
SMS 큐와 이메일 큐를 분리하지 않으면, 대량 이메일 발송이 시작될 때 긴급 SMS 전달이 수 분씩 지연될 수 있다. 채널별 독립 큐는 채널 간 격리를 보장하고, 각 채널의 처리 속도와 우선순위를 독립적으로 제어할 수 있게 해준다. Kafka 기반이라면 토픽을 채널별로 분리하고, 파티션 수를 채널의 처리량에 맞게 조정한다.
알림 우선순위 — Priority Queue
모든 알림이 동등하지 않다. 계정 보안 경고와 프로모션 쿠폰 발송이 같은 큐에서 같은 속도로 처리되어선 안 된다. 알림 우선순위를 명시적으로 정의하고, 우선순위별 큐를 운용해 높은 우선순위 알림이 항상 먼저 처리되도록 해야 한다.
중복 방지 — 멱등성 보장
분산 시스템에서 재시도와 중복 발송은 불가피하다. 네트워크 지연으로 타임아웃이 발생해도 외부 서비스에 이미 전달되었을 수 있고, 워커가 처리 도중 크래시하면 메시지를 재처리한다. 사용자가 동일한 알림을 두 번 받는 것은 신뢰도 하락으로 이어진다.
해결책: Idempotency Key + Redis 중복 필터
💡 Idempotency Key 설계 원칙: 비즈니스 의미가 담긴 키를 사용한다. 단순 UUID보다 "order:98765:completed", "user:12345:login_otp:2024011510" 처럼 이벤트의 의미와 시간 윈도우를 포함하면, 같은 이벤트의 재시도는 걸러내되 다음 로그인 시도는 새로운 알림으로 처리할 수 있다.
재시도 전략 — 신뢰할 수 있는 전달
외부 알림 게이트웨이(FCM, APNs, SendGrid)는 일시적으로 장애가 발생하거나 요청을 거부할 수 있다. 단순히 실패를 버리면 알림 유실이 발생한다. 체계적인 재시도 전략이 필수다.
Exponential Backoff with Jitter
Dead Letter Queue (DLQ)
재시도 횟수를 모두 소진한 알림은 Dead Letter Queue로 이동시킨다. DLQ는 유실을 방지하고, 운영자가 실패 원인을 분석하거나 수동으로 재처리할 수 있는 안전망이다. DLQ에 쌓인 메시지가 임계값을 초과하면 즉시 알람을 발송해야 한다.
| 오류 유형 | 예시 | 재시도 여부 | 처리 방법 |
|---|---|---|---|
| 일시적 오류 | 5xx, 타임아웃, Rate Limit | 재시도 | Exponential Backoff 후 재시도 |
| 영구 오류 | 무효 토큰, 구독 해제, 4xx | 재시도 금지 | 토큰 삭제 / 수신 거부 처리 |
| TTL 만료 | 유효 기간 초과 | 폐기 | 미전달 로그 기록 후 폐기 |
| 재시도 소진 | 일시적 오류 max 횟수 초과 | 수동 검토 | DLQ로 이동, 운영자 알림 |
사용자 설정 — 알림 수신 제어
사용자가 원하지 않는 알림을 수신하면 앱 삭제, 이메일 수신 거부, 법적 문제(CAN-SPAM, GDPR)로 이어진다. 세밀하고 직관적인 알림 수신 설정은 사용자 신뢰와 직결된다.
⚠️ 방해 금지 시간대와 Critical 알림: 보안 경고나 결제 오류 같은 CRITICAL 알림은 방해 금지 시간대에도 반드시 전달해야 한다. 사용자 설정 조회 시 override_critical: true 플래그를 확인하고, CRITICAL 우선순위 알림은 quiet_hours를 무시하는 로직을 명시적으로 구현해야 한다.
사용자 설정은 Redis에 캐싱해 매 알림마다 DB를 조회하는 부하를 없애야 한다. 설정 변경 시에는 캐시를 즉시 무효화(Invalidation)해야 한다. GDPR 등 데이터 규정에 따라 사용자가 언제든 모든 알림을 철회할 수 있어야 하며, 이 설정 변경은 즉시 반영되어야 한다.
알림 템플릿과 개인화
각 채널은 콘텐츠 형식이 다르다. Push 알림은 제목+본문 100자 이내, 이메일은 HTML 전체 페이지, SMS는 160자 내외다. 동일한 이벤트를 채널별로 적절한 형식으로 렌더링하는 템플릿 시스템이 필요하다.
다국어 지원과 개인화
글로벌 서비스라면 동일 템플릿을 언어(locale)별로 관리해야 한다. 사용자의 언어 설정, 이름, 구매 이력 등을 활용한 개인화는 클릭률을 크게 높인다. 단, 개인화 데이터는 렌더링 시점에 실시간으로 주입하되 민감 정보는 절대 포함하지 않는다. 템플릿 변경 시에는 버전 관리로 A/B 테스트와 롤백이 가능해야 한다.
모니터링과 분석
알림 시스템의 건강도는 정량적으로 측정되어야 한다. 전달 성공률, 지연 분포, 열람률, 재시도율, DLQ 적재량은 반드시 실시간으로 추적해야 하는 지표다.
| 지표 | 설명 | 임계값(예시) | 대응 |
|---|---|---|---|
| 전달 성공률 | 전송 시도 대비 성공 비율 | < 99% 시 알람 | 채널별 게이트웨이 상태 확인 |
| 전달 지연 (p99) | 이벤트 발생부터 전달까지 시간 | CRITICAL > 2s 시 알람 | 큐 적체 여부, 워커 수 조정 |
| 열람률 (Open Rate) | 전달된 알림 중 실제 열람 비율 | Push < 5% 시 검토 | 템플릿, 타겟팅, 발송 시간 최적화 |
| 재시도율 | 전체 전송 중 재시도 발생 비율 | > 5% 시 알람 | 외부 게이트웨이 이상 여부 확인 |
| DLQ 적재량 | Dead Letter Queue 메시지 수 | > 1,000건 시 알람 | 즉시 운영자 개입, 원인 분석 |
| 수신 거부율 | 이메일 Unsubscribe / Push 권한 해제 | 이메일 > 0.5% 시 검토 | 발송 빈도, 콘텐츠 관련성 재검토 |
정리 및 핵심 교훈
알림 시스템은 단순한 메시지 전송 서비스가 아니다. 신뢰성, 확장성, 사용자 경험이 교차하는 복잡한 분산 시스템이다. 잘 설계된 알림 시스템은 사용자가 필요한 정보를 정확한 순간에 받게 해주고, 나쁜 알림 시스템은 사용자를 짜증나게 해 앱 삭제로 이어진다.
채널은 독립적으로 격리하라
채널별 큐와 워커를 분리하면 마케팅 이메일 대량 발송이 긴급 OTP 전달을 지연시키는 일이 없다. 격리가 신뢰성의 기반이다.
멱등성은 설계 초기부터
재시도를 허용하면서도 중복 전달을 막으려면 Idempotency Key와 Redis 중복 필터를 처음부터 설계에 포함해야 한다. 나중에 추가하는 것은 훨씬 어렵다.
우선순위가 SLA를 결정한다
모든 알림을 동등하게 처리하면 결국 아무것도 제때 도착하지 않는다. 우선순위별 큐와 워커를 명확히 분리해야 한다.
사용자 설정을 존중하라
GDPR, CAN-SPAM 같은 법적 요건은 차치하더라도, 원치 않는 알림을 보내는 것은 사용자 신뢰를 잃는 가장 빠른 방법이다.
전달률을 실시간으로 측정하라
DLQ 적체와 전달 지연은 문제가 이미 심각해진 뒤에야 알게 된다. 실시간 대시보드와 임계값 알람이 필수다.
외부 게이트웨이 장애를 가정하라
APNs, FCM, SendGrid는 언제든 다운될 수 있다. 큐로 버퍼링하고, 서킷 브레이커와 폴백 채널을 사전에 설계해야 한다.
💬 설계 인터뷰 팁: 알림 시스템 문제에서 면접관이 가장 듣고 싶어하는 것은 세 가지다. 첫째, 채널을 어떻게 분리하고 확장할 것인가. 둘째, 중복 전달과 유실을 동시에 어떻게 방지할 것인가. 셋째, 외부 서비스(APNs/FCM) 장애 시 시스템이 어떻게 동작할 것인가. 이 세 가지에 명확한 답변을 준비하면 핵심은 모두 커버된다.
댓글