[대규모 시스템 설계 기초] 10장. 알림 시스템 설계

알림 시스템 설계 개요
알림 시스템은 이벤트, 선물 중요할 만한 정보를 비동기적으로 제공합니다. 알림 시스템은 단순히 모바일 푸시 알림에 한정되지 않습니다.
단일 이벤트 트리거 기반 멀티 채널 알림 방송 시스템을 목표로 합니다.
1단계 문제 이해 및 설계 범위 확정
대상은 푸시 알림, SMS 메시지, 그리고 이메일이 될 수 있습니다. 실시간 시스템임을 감안한다. 지원하는 단말은 iOS 단말, 안드로이드 단말, 그리고 랩톱/데스크톱입니다.
기능적 요구사항
- 지원 알림 유형: 푸시, SMS, 이메일
비기능적 요구사항
- 성능 특성: 연성 실시간(soft real-time) 시스템, 높은 부하 시 약간의 지연 허용
- 사용자 설정: opt-out 기능(사용자가 알림을 받지 않도록하는 기능) 지원
중요한건 확장성을 고려해 천만 건의 모바일 푸시 일림, 백만 건의 SMS 메시지, 5백만 건의 이메일 보낼 수 있어야 합니다.
알림 이벤트 처리 Flow

Event Producer - 알림을 보내는 쪽으로 이벤트 발행을 담당합니다. Trigger 역할을 수행하고 비즈니스 로직에서 이벤트 객체를 발행합니다.
Notification Queue - 비동기 처리를 위한 중간 버퍼 역할을 합니다. 이걸 메시지 큐라고 정의하겠습니다. 순간적인 버스트 트래픽이 들어온다 하더라도 Producer - Service 사이에 결합도가 낮아 서비스 장애 전파로 이어질 확률이 낮아지게 됩니다. 이는 사용자에게도 서비스 경험 영향을 적게 받을 수 있는 포인트입니다.
Notification Service - 큐에서 이벤트를 읽어서 채널별 발송 전략을 결정하게 됩니다.
Channel Adapter - Notification Service 의 호출을 받아서 실제로 발송 역할을 수행하게 됩니다. 백엔드 뒷단으로 외부 시스템 API 연동을 수행할 수 있습니다. Adapter 란 인터페이스를 제공하므로 확장성에 용이할 수 있습니다.
단말 토큰
- 페이로드
- 알림 내용을 담은 JSON 딕셔너리이다.
{
"aps" : {
"alert" : {
"title": "Game Reqeust", //알림 제목
"body" : "body", //알림 본문
"action-loc-key":"PLAY" //액션 키
},
"badge": 5 //앱 아이콘 배지 카운트
}
}
처리량 가정
- 예상 TPS : 5,000 ~10,000 건 발송 처리
- 큐 기반 비동기 처리로 발송 서버 부하 분산
- 실패 건 재시도 정책 : N회 간격 / DLQ 이동
2단계 개략적 설계안 제시 및 동의 구하기
전체 알림 흐름은 다음과 같습니다.
애플리케이션 서버(API)는 사용자 이벤트(예: 결제 완료, 친구 요청 등)를 감지하면 APNS 또는 FCM을 통해 단말로 메시지를 전달합니다.
iOS 단말은 APNS를 통해, Android 단말은 FCM을 통해 알림을 수신합니다.
알림 유형별 지원
iOS 푸시 알림
알림 제공자 -> APNS -> iOS 단말
- APNS : 애플이 제공하는 원격 서비스. 푸시 알림을 IOS 장치로 보내는 역할을 담당
- iOS 단말 : 푸시 알림을 수신하는 사용자 단말
안드로이드 푸시 알림
APNS 대신 FCM 을 사용한다.
연락처 정보 수집 절차
알림을 보내려면 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보가 필요합니다.
API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장합니다.
device_token 관리 정책
단말 토큰은 앱 설치/재로그인 시마다 변경될 수 있으므로 주기적인 갱신이 필요합니다.
하나의 사용자가 여러 기기를 사용할 수 있으므로, user_id 기준 다대일(1:N) 관계를 유지해야 합니다.

알림 전송 및 수신 절차
1부터 N까지 서비스 마이크로 서비스, 크론잡 등 시스템 컴포넌트라고 하면 실제로 구현되는 서비스를 고려해봤을때 과금 서비스, 배송 알림을 보내는 쇼핑몰 등이 그 예가 됩니다.
알림 시스템 : 서비스 1-N 에 알림 전송을 위한 API 제공해야되고 제 3자 서비스에 전달할 알림 페이로드를 만들어야 합니다.
제 3자 서비스 : 국가, 지역에 맞춰 서비스 가능한 지역인지 확인해보고 서비스를 사용해야 합니다.
각 서비스에서 알림 서버로 알림 생성 요청을 보내게 된다. 알림 서버는 DB에 저장되어 있는 사용자의 메타 데이터를 조합해 알림 데이터를 생성하게 됩니다. 그리고 이 알람은 알림에 맞는 이벤트(안드로이드 푸시 알림, iOS 푸시 알림 등)를 생성해 해당 이벤트를 위한 목적으로 큐에 넣게 됩니다. 디바이스 푸시 큐(메시지 큐)에 쌓여있는 알림은 작업 서버가 꺼내서 알림 서비스로 전달합니다.
전체 아키텍처는 이벤트 기반 비동기 처리 구조로 설계되어 있습니다. 서비스 서버는 알림 이벤트를 생성해 알림 서버로 전달하고, 알림 서버는 이를 큐에 적재하여 실제 발송 작업을 비동기로 분리해야 합니다. 메시지 큐는 대량 트래픽 상황에서 버퍼 역할을 하며, 발송 실패 시 재시도(Backoff Retry) 및 DLQ(Dead Letter Queue)로 안정성을 보장해야 합니다.
메시지 큐를 도입하게 됨으로써 알림 데이터 유실을 막을 수 있고 컴포넌트간 의존성을 최소화할 수 있다. 만약, 메시지 큐가 존재하지 않았다면 알림 시스템의 작업이 끝날때까지 기다려야 다음 작업을 실행할 수 있을 것입니다. 아래 아키텍처에서 메시지 큐를 추가해 줬기에 알림 서버와 써드파티 서비스는 의존성을 최소화하여 할 수 있게 되었습니다. 또, 메시지 큐를 도입하면서 이메일, SMS, APN, FCM 등 어느 하나의 서비스가 장애가 발생한다 하더라도 나머지 유형의 알림은 정상적으로 보내게 됩니다.

process
- 서비스에서 알림 이벤트(API)를 호출해 알림 서버로 전달합니다.
- 알림 서버는 사용자의 단말 정보(토큰, 이메일 등)를 캐시 또는 데이터베이스에서 조회합니다.
- 알림 서버는 조회한 정보를 기반으로 알림 이벤트를 생성하고, 이를 디바이스 푸시 큐에 적재합니다.
- 작업 서버는 큐에서 알림 이벤트를 소비(consume)하고, 발송을 위한 데이터를 가공합니다.
- 작업 서버는 처리 결과를 제3자 제공 서비스(APNS, FCM, SMS 게이트웨이 등) 로 전송합니다.
- 제3자 제공 서비스는 실제 사용자 단말로 알림을 전달합니다.
- 발송 실패 시, 작업 서버는 오류를 감지하고 디바이스 푸시 큐로 재시도 이벤트를 다시 보낸다.
상세설계
안정성
데이터 손실 방지
- 알림은 지연되거나 순서가 틀려도 되지만 사라지면 문제가 된다. 알림 시스템은 알림 데이터를 데이터베이스에 보관한다. 재시도 메커니즘을 구현해야 합니다.
- 알림 데이터는 발송 전과 발송 후 모두 로그에 남겨야 합니다.
- 발송 전: 큐 적재 직후 상태(PENDING)
- 발송 중: 작업 서버가 수신했을 때(PROCESSING)
- 발송 완료: APNS/FCM 응답을 받은 후(SUCCESS / FAIL)
- 알림 로그 데이터베이스를 유지하는것도 하나의 방법이 될 수 있습니다.
- 알림이 도착하면 이벤트 ID 를 검사해서 이전에 본 적이 있는 이벤트인지 검사합니다. 중복되는 이벤트이면 버리고 그렇지 않으면 알림을 발송합니다.
- 알림 시스템은 네트워크 오류, 타임아웃 등으로 인해 동일한 이벤트가 여러 번 재시도될 수 있다. 따라서 Idempotent(멱등) 설계가 필수적이다. 각 알림에는 고유한 event_id를 부여하고, DB에 해당 ID를 기록한 뒤 이미 처리된 이벤트라면 무시하도록 합니다. 이렇게 하면 메시지 재시도나 큐 소비 중복에도 불구하고 동일 알림이 여러 번 발송되지 않습니다.

위 아키텍처를 수정하면 아래와 같습니다.
알림 서버는 사용자 수가 증가할수록 부하가 급격히 늘어날 수 있으므로, 인증(Authentication)·전송률 제한(Throttling)·모니터링 시스템을 함께 구축해야 합니다. 이를 통해 시스템의 안정성을 유지하고, 장애 발생 시 원인을 신속히 추적할 수 있습니다.

추가로 고려해야할 사항
- 템플릿 이용, 일관성 유지 및 오류 가능성을 줄일 수 있습니다.
알림 설정
- 사용자가 알림 설정을 상세히 조정할 수 있도록 합니다.
| 컬럼명 | 타입 | 설명 |
| user_id | bigint | 비고 |
| channel | varchar | 알림이 전솔될 채널, 푸시 알림, 이메일, SMS 등 |
| opt_in | boolean | 해당 채널로 알림을 받을 것인지 여부 |
| updated_at | timestamp | 마지막 알림 설정 변경 시각 |
전송률 제한
동일 사용자에게 단시간 내 과도한 알림을 보내지 않도록 사용자 채널별 전송률 제한을 적용합니다.
- 동일 사용자 분당 최대 N건, Redis 를 활용해 손쉽게 구현할 수 있습니다.
재시도 방법
- 재시도 정책은 지수형 백오프(Exponential Backoff) 방식으로 구현할 수 있습니다.
예를 들어 1분 → 5분 → 15분 → 1시간 간격으로 최대 5회 재시도 후 실패 처리합니다.
실패한 알림은 DLQ(Dead Letter Queue)에 별도 저장하여 후속 점검 또는 수동 복구에 사용합니다.
모니터링
- 큐에 쌓인 알림의 개수가 크면 이벤트를 빠르게 처리하지 못하고 있다는 지표가 된다. 그러므로 아래와 같은 지표를 시각화해두면 장애 원인 분석에 도움이 될 수 있다.
- 큐 대기 메시지 수 (pending_message_count)
- 평균 처리 시간 (avg_processing_time_ms)
- 실패율 (fail_rate_per_channel)
- 재시도 횟수 (retry_count)
- APNS/FCM 응답 코드 분포
ref
https://dewble.tistory.com/entry/system-design-notification'IT' 카테고리의 다른 글
| MongoDB Covered Index 이해하기 (0) | 2025.11.23 |
|---|---|
| Spring AOP로 Controller 파라미터 자동 주입하기 (0) | 2025.11.16 |
| [대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 3 (0) | 2025.11.02 |
| [대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 2 (0) | 2025.10.19 |
| [대규모 시스템 설계 기초] 4장. 처리율 제한 장치의 설계 - 1 (0) | 2025.10.19 |
댓글
이 글 공유하기
다른 글
-
MongoDB Covered Index 이해하기
MongoDB Covered Index 이해하기
2025.11.23 -
Spring AOP로 Controller 파라미터 자동 주입하기
Spring AOP로 Controller 파라미터 자동 주입하기
2025.11.16 -
[대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 3
[대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 3
2025.11.02 -
[대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 2
[대규모 시스템 설계 기초] 4장. 처리율 제한 장치의설계 - 2
2025.10.19