
- notification system
- 중요할 만한 정보를 비동기적으로 제공
- Mobile push notification, SMS 메시지, Email
1. 1단계 문제 이해 및 설계 범위 확정
- 어떤 종류의 알림을 지원?
- real-time (실시간) 시스템?
- soft real-time 시스템이라 가정
- 가능한 한 빨리 전달 / but, 높은 부하가 걸렸을 때 약간의 지연은 무방
- 어떤 종류의 단말을 지원?
- iOS 단말, android 단말, laptop/desktop 지원
- 보낼 알림은 누가 생성 가능?
- 사용자가 알림을 받지 않도록 opt-out 설정 가능?
- 하루에 몇 건의 알림?
- 천만 건의 모바일 푸시 알림 / 백만 건의 SMS 메시지 / 5백만 건의 이메일
2. 2단계 개략적 설계안 제시 및 동의 구하기
알림 유형별 지원 방안
iOS 푸시 알림
- 3가지 컴포넌트 필요: 알림 provider, APNS, iOS device
- 알림 provider
- notification request 만들어 애플 푸시 알림 서비스(APNS)로 보내는 주체
- notification request
- device token: 알림 요청을 보내는 데 필요한 고유 식별자
- payload: 알림 내용을 담은 JSON dictionary
- APNS: 애플이 제공하는 원격 서비스, 푸시 알림을 iOS 장치로 보내는 역할
- iOS device: 푸시 알림을 수신하는 사용자 단말
안드로이드 푸시 알림
- APNS 대신 FCM(Firebase Cloud Messaging) 사용
SMS 메시지
- Twilio, Nexmo 같은 제3사업자의 서비스 이용
이메일
- Sendgrid, Mailchimp 같은 상용 이메일 서비스 이용
- 전송 성공률 ⬆️, 데이터 분석 서비스 analytics 제공
연락처 정보 수집 절차
- 이메일 주소와 전화번호는 user 테이블에 / 단말 토큰은 device 테이블에
- 한 사용자가 여러 단말 가질 수 있고, 알림은 모든 단말에 전송되어야 한다는 점을 고려
알림 전송 및 수신 절차
개략적 설계 (초안)
- notification system
- 알림 전송/수신 처리의 핵심
- 1개 서버만 사용하는 시스템이라고 가정.
- 서비스 1~N에 알림 전송을 위한 API 제공 필요
- 제3자 서비스에 전달할 알림 payload 만들어 낼 수 있어야 함
- third party services
- 사용자에게 알림을 실제로 전달하는 역할
- 제3자 서비스와의 통합을 진행할 때 유의할 것 = 확장성
extensibility
- 쉽게 새로운 서비스를 통합, 기존 서비스를 제거
- 중국에서는 FCM 사용 불가. (대신 Jpush, PushY)
- iOS, 안드로이드, SMS, 이메일 단말: 사용자는 자기 단말에서 알림을 수신
- 이 설계의 문제점
- SPOF: 알림 서비스에 서버가 하나 뿐.
- 규모 확장성: 한 대 서비스로 푸시 알림에 관계된 모든 것을 처리
→ 데이터베이스나 캐시 등 중요 컴포넌트의 규모를 개별적으로 늘릴 방법 X
- 성능 병목
개략적 설계 (개선된 버전)
- 개선 방향
- 데이터베이스와 캐시를 알림 시스템의 주 서버에서 분리
- 알림 서버를 증설하고 자동으로 수평적 규모 확장이 이루어질 수 있도록
- 메시지 큐를 이용해 시스템 컴포넌트 간의 강결합 끊음
- notification server
- 알림 전송 API: 스팸 방지를 위해 보통 사내 서비스 또는 인증된 클라이언트만 이용 가능
- 알림 validation: 이메일 주소, 전화번호 등에 대한 기본적 검증을 수행
- 데이터베이스 또는 캐시 질의: 알림에 포함시킬 데이터를 가져오는 기능
- 알림 전송: 알림 데이터를 메시지 큐에 넣음
→ 하나 이상의 메시지 큐 사용해서 알림 병렬 처리
- cache
- 사용자 정보, 단말 정보, 알림 template 등을 캐시
- DB
- message queue
- 시스템 컴포넌트 간 의존성 제거하기 위해 사용
- 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할도 함
- workers
- message queue에서 전송할 알림을 꺼내서 제3자 서비스로 전달하는 역할
알림 전송 과정
- API 호출 → notification server로 알림 보냄
- notification server: 사용자 정보, 단말 토큰, 알림 설정 같은 metadata를 캐시나 데이터베이스에서 가져옴
- notification server: 전송할 알림에 맞는 이벤트 생성 → 해당 이벤트를 위한 queue에 push
- worker server: message queue에서 알림 이벤트 pop
- worker server: 알림을 third-party service로 전송
- third-party service: user device로 알림 전송
3. 3단계 상세 설계
안정성
안정성을 확보하기 위해 고려해야하는 사항
데이터 손실 방지
- 어떤 상황에서도 알림이 소실되면 안 됨!
- 알림 데이터를 DB에 보관, 재시도 매커니즘 구현 필요
- notification log 데이터베이스 유지
알림 중복 전송 방지
- 분산 시스템 특성상 가끔은 같은 알림이 중복되어 전송되기도 함
- 중복 탐지 매커니즘 도입
- ex. 보내야 할 알림이 도착하면 그 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 확인.
- 오류를 신중하게 처리
- 중복 전송을 100% 방지하는 것은 불가능
추가로 필요한 컴포넌트 및 고려사항
알림 템플릿
- 알림 메시지 대부분은 형식이 비슷. 유사성을 고려하자!
- parameter, 스타일, tracking link 만 조정
- 오류 가능성, 알림 작성 시간 ⬇️
알림 설정
- 사용자가 알림 설정을 상세히 조정할 수 있도록
- 알림 설정 테이블에 보관
user_id
channel 알림이 전송될 채널
opt_in: boolean 알림을 받을 것인지의 여부
- 특정 알림 보내기 전에 반드시 해당 사용자가 알림을 켜 두었는지 확인
전송률 제한
- 한 사용자가 받을 수 있는 알림의 빈도를 제한
- 알림을 너무 많이 보내기 시작하면 사용자가 알림 기능을 꺼 버릴 수도 있기 때문에 중요
재시도 방법
- 알림 전송에 실패하면 해당 알림을 재시도 전용 queue에 push
- 같은 문제가 계속 발생 시 개발자에게 alert
푸시 알림과 보안
- iOS, Android 앱의 경우: 알림 전송 API는 appKey와 appSecret 사용해서 보안 유지
- authenticated, verfied 클라이언트만 해당 API를 사용하여 알림 전송 가능
큐 모니터링
- queue에 쌓인 알림의 개수 ← 중요한 metric
- 너무 크면, 작업 서버들이 이벤트를 빠르게 처리하고 있지 못하다는 뜻 → 작업 서버 증설하는 게 바람직
이벤트 추적
- 알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 메트릭
- analytics는 보통 이벤트 추적 기능도 제공
- 보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합 필요
수정된 설계안
- 알림 서버에 authentication과 전송률 제한 rate-limiting 기능 추가
- 전송 실패에 대응하기 위한 재시도 기능이 추가
- 전송에 실패한 알림은 다시 queue에 넣고
- 지정된 횟수만큼 재시도
- 전송 템플릿을 사용하여 알림 생성 과정을 단순화 → 알림 내용의 일관성 유지
- 모니터링, 추적 시스템을 추가 → 시스템 상태 확인, 추후 시스템 개선 용이