알림 시스템은 최근 많은 프로그램들이 채택한 인기 있는 기능이다.
고객에게 중요할 만한 정보를 비동기적으로 제공한다.
- 모마일 푸시 알림
- SMS 메시지
- 이메일
1단계: 문제 이해 및 설계 범위 확정
하루에 백만 건 이상의 알림을 처리하는 확장성 높은 시스템을 구축하는건 쉬운 과제가 아니다.
알림 시스템이 어떻게 구현되는지에 대한 깊은 이해가 필요하다.
- Q. 어떤 종류의 알림을 지원해야하는가?
- A. 푸시 알림, SMS 메시지, 이메일
- Q. 실시간 시스템?
- A. 연성 실시간 시스템 > 빨리 전달해야하지만 시스템의 부하가 심할 때 약간의 지연은 무방함
- Q. 지원 단말?
- A. IOS, 안드로이드, 랩톱/데스크톱
- Q. 알림은 누가 만들 수 있는가?
- A. 클라이언트 애플리케이션, 서버측 스케쥴링
- Q. 알림 거부 가능?
- A. 예
- Q. 하루 몇 건의 알림 처리?
- A. 천만 건 푸시 알림, 백만 건 SMS, 5백만 건 이메일
2단계: 개략적 설계안 제시 및 동의 구하기
알림 유형 별 지원 방안
유형에 따라 동작하는 알림 메커니즘에 차이가 있다.
IOS 푸시 알림
IOS에서 푸시 알림을 보내기 위해서는 3가지 컴포넌트가 필요하다.
- 일림 제공자(provider)
- 알림 요청을 만들어 애플 푸시 알림 서비스(APNS)로 보내는 주체로 두개의 정보가 필요하다.
- 단말 토큰: 알림 요청을 보내는 데 필요한 고유 식별자
- 페이로드: 알림 내용을 담은 JSON 딕셔너리
1 2 3 4 5 6 7 8 9 10
{ "aps": { "alert" : { "title": "Game Request", "body": "Bob wants to play chess", "action-loc-key": "PLAY" }, "badge": 5 } }
- APNS
- 애플이 제공하는 원격 서비스
- 푸시 알림을 IOS 장치로 보내는 역할을 담당.
- IOS 단말
- 푸시 알림을 수신하는 사용자의 단말
안드로이드 푸시 알림
APNS를 사용하는 IOS와 달리 FCM(Firebase Cloud Messaging)을 사용한다.
SMS 메시지
트윌리오(Twilio), 넥스모(Nexmo)같은 제3 사업자의 서비스를 많이 이용한다.
이메일
대부분 고유 이메일 서버를 구축할 역량을 가지고 있지만, 상용 이메일 서비스를 이용한다.
- 센드그리드, 메일침프
지금까지의 언급한 모든 알림 유형을 한 시스템으로 묶어면 아래와 같다.
연락처 정보 수집 절차
알림을 보내기 위해 모바일 단말 토큰, 전화번호, 이메일 주소 등 정보가 필요하다.
사용자가 앱을 설치하거나 처음으로 계정을 등록할 때 API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장한다.
필수적인 정보만 포함한 스키마는 아래와 같다.
erDiagram USER { bigint user_id varchar email integer coutry_code integer phone_number timestamp created_at } DEVICE { bigint id varchar device_token bigint user_id timestamp last_logged_in_at }
- 이메일 주소와 전화번호는
USER
테이블에 저장하고, 단말 토큰은DEVICE
테이블에 저장한다. - 한 사용자가 여러 단말을 가질 수 있다.
- 알림은 모든 단말에 전송되어야 한다.
알림 전송 및 수신 절차
개략적으로 설계하고 점차적으로 최적화한다.
개략적 설계안(초안)
서버를 1대만 사용하는 시스템이라 가정한다.
- Service 1 ~ N
- 마이크로서비스, 크론잡, 분산 시스템 컴포넌트 일 수 있다.
- 알림 시스템
- 알림 전송/수신 처리의 핵심
- Service 1 ~ N에 알림 전송을 위한 *API 제공
- 제3자 서비스에 전달할 알림 페이로드 생성
- 확장성을 유의해야함, 쉽게 새로운 서비스를 통합하거나 기존 서비스를 제거할 수 있어야함
- 어떤 서비스는 다른 시장에서는 사용할 수 없을 수도 있다. (FCM은 중국서 사용불가)
- 단말
위와 같은 설계에는 몇 가지 문제가 있다.
- SPOF
- 알림 서비스에 서버가 하나 뿐이라 서버 장애 발생시 전체 서비스 장애로 이어진다.
- 규모 확장성
- 한 대 서비스로 푸시 알림에 관계된 모든 것을 처리하므로, 데이터베이스나 캐시 등 중요 컴포넌트의 규모를 개별적으로 늘릴 수 없다.
- 성능 병목
- 알림을 처리하고 보내는 것은 자원을 많이 필요로할 수 있어, 트래픽이 몰리면 과부하 상태에 빠질 수 있다.
- HTML 페이지 생성
- 제3자 서비스의 응답 대기
- 알림을 처리하고 보내는 것은 자원을 많이 필요로할 수 있어, 트래픽이 몰리면 과부하 상태에 빠질 수 있다.
개략적 설계안(개선)
최초 개략적 설계안에서 다음과 같은 문제를 개선했다.
- 데이터베이스와 캐시를 알림 시스템에서 분리
- 알림 서버 증설 및 자동 수평 규모 확장 추가
- 메시지 큐를 이용해 시스템 컴포넌트 사이의 강한 결합을 끊는다.
- 서비스(1~N)
- 알림 시스템 서버의 API를 통해 알림을 보낼 서비스들
- 알림 서버
- 알림 전송 API
- 스팸 방지를 위해 사내 서비스 또는 인증된 클라이언트만 이용 가능
- 알림 검증
- 이메일, 전화번호 등 기본적 검증 수행
- 데이터베이스 또는 캐시 질의
- 알림에 포함시킬 데이터를 가져온다.
- 알림 전송
- 알림 데이터를 메시지 큐에 넣는다.
- 하나 이상의 메시지 큐를 이용하면 병렬적으로 처리할 수 있다.
- 알림 전송 API
- 캐시
- 사용자 정보, 단말 정보, 알림 템플릿 등을 캐시한다.
- DB
- 사용자, 알림, 설정 등 다양한 정보 저장
- 메시지 큐
- 시스템 컴포넌트 간 의존성을 제거한다.
- 다량의 알림이 전송되어야 하는 경우 버퍼 역할도 한다.
- 작업 서버
- 메시지 큐에서 전송할 알림을 꺼내 제3자 서비스로 전달한다.
3단계: 상세 설계
안정성
분산 환경에서 운영될 알림 시스템을 설계할 때는 안정성을 확보하기 위한 사앙 몇 가지를 반드시 고려해야한다.
데이터 손실 방지
알림 전송 시스템의 가장 중요한 요구사항 가운데 하나는 어떤 상황에서도 알림이 소실되면 안된다는 것이다.
- 지연되거나 순서가 달라도 사라지면 안된다
이를 위해 알림 데이터를 데이터베이스에 보관하고 재시도하는 메커니즘을 구현해야 한다.
알림 중복 전송 방지
같은 알림이 여러 번 반복되는 것을 완전히 막는 것은 불가능하다.
그 빈도를 줄이기 위해 중복을 탐지하는 매커니즘을 도입하고, 오류를 신중하게 처리해아한다.
- 보내야 할 알림이 도착하면 그 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 살핀다.
- 중복된 이벤트면 버리고, 그렇지 않으면 알림을 발송한다.
추가로 필요한 컴포넌트 및 고려사항
알림 템플릿
알림 메시지 대부분은 형식이 비슷하다.
알림 템플릿은 이런 유사성을 고려하여, 알림 메시지의 모든 부분을 처음부터 다시 만들 필요 없도록 한다.
- 사전에 지정한 형식에 맞춰 알람을 만들어 내는 틀이다.
- 전송될 알림들의 형식을 일관성 있게 유지할 수 있다.
- 오류 가능성뿐 아니라 알림 작성에 드는 시간도 줄일 수 있다.
알림 설정
사용자가 알림 설정을 상세히 조정할 수 있도록 한다.
erDiagram OPT { bigint user_id varchar channel boolean opt_in }
이와 같은 설정을 도입했다면 알람을 보내기 전 반드시 해당 사용자가 알림을 켜 두었는지 확인해야한다.
전송률 제한
한 사용자가 받을 수 있는 알림의 빈도를 제한하여 사용자에게 많은 알림을 보내지 않도록 할 수 있다.
- 알림을 너무 많이 보내기 시작하면 사용자가 알림 기능을 꺼버릴 수 있다.
재시도 방법
써드 파티 서비스가 알림 전송에 실패하면, 해당 알림을 재시도 전용 큐에 넣고 같은 문제가 계속해서 발생하면 개발자에게 통지한다.
푸시 알림과 보안
IOS와 안드로이드 앱의 경우, 알림 전송 API는 appKey와 appSecret을 사용하여 보안을 유지한다.
이러한 방식으로 인증된 혹은 승인된 클라이언트만 해당 API를 사용할 수 있다.
큐 모니터링
큐에 쌓인 알림의 개수를 보고 작업 서버들의 처리량을 쉽게 모니터링 할 수 있다.
- 너무 크면 이벤트를 빠르게 처리하지 못하고있다는 뜻
이벤트 추적
알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 메트릭은 사용자를 이해하는데 중요하다.
보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합하는 경우가 많다.
수정된 설계안
이전 설계안과의 차이점은 아래와 같다.
- 알림 서버에 인증과 전송률 제한 기능이 추가
- 전송 실패에 대응하기 위한 재시도 기능 추가
- 다시 큐에 넣고 지정된 횟수만큼 재시도
- 전송 템플릿을 사용하여 알림 생성 과정을 단순화하고 알림 내용의 일관성을 유지
- 모니터링과 추적 시스템 추가
4단계: 마무리
규모 확장이 쉬울 뿐 아니라 푸시 알림, SMS 메시지, 이메일 등 다양한 정보 전달 방식을 지원하는 알림 시스템을 구축했다.
시스템 컴포넌트 사이의 결함도를 낮추기 위해 메시지 큐를 적극적으로 사용하였다.
- 안정성
- 메시지 전송 실패율을 낮추기 위해 안정적인 재시도 메커니즘을 도입
- 보안
- 인징된 클라이언트만이 알림을 보낼 수 있도록 보안 매커니즘 추가(appKey, appSecret)
- 이벤트 추적 및 모니터링
- 사용자 설정
- 사용자가 알림 수신 설정을 조정할 수 있도록 함
- 알람을 보내기 전 해당 설정을 확인하도록 스스템 설계를 변경
- 전송률 제한
- 사용자에게 알림을 보내는 빈도를 제한할 수 있도록 함