10장 알림 시스템 설계
가상 면접 사례로 배우는 대규모 시스템 설계 기초 – System Design Interview
이 책에서는 iOS 푸시, 안드로이드 푸시, SMS 메시지, 이메일 에 대해서 다룬다.
한국 기준으로는 알림톡도 적용할 수 있을 것이며 요즘에는 웹 푸시에 점차 활성화 되어가고 있기 때문에 해당 부분도 고려하면 좋을 것이다.
서드파티를 이용하다보면 별별 일이 다 발생된다.
따라서 본문에서 나온대로 오류시 재시도를 할 수 있게 시스템을 구성하거나
오류 발생 시 업무 담당자가 수동으로 트리거 하여 발송할 수 있도록 처리를 해주는 것이 좋을 것이다.
또한 기기 변경 / 연락처 정보 변경 이 발생되었을 경우 어떻게 처리할지에 대한 부분도 고려하면 좋을 것이다.
1단계 문제 이해 및 설계 범위 확정
질문 예시
- 어떤 종류의 알림을 지원해야 하나요?
- 실시간 시스템이어야 하나요?
- 어떤 종류의 단말을 지원해야 하나요?
- 사용자에게 보낼 알림은 누가 만들 수 있나요?
- 사용자가 알림을 받지 않도록(opt-out) 설정할 수도 있어야 하나요?
- 하루에 몇 건의 알림을 보낼 수 있어야 하나요?
2단계 개략적 설계안 제시 및 동의 구하기
알림 유형별 방안
iOS 푸시 알림
iOS에서 푸시 알림을 보내기 위해서는 세가지 컴포넌트가 필요하다.
- 알림 제공자(provider)
알림 요청을 만들려면 다음과 같은 데이터가 필요하다.
- 단말 토큰 : 기기 식별자
- 페이로드 : 알림 내용
- APNS
애플이 제공하는 원격 서비스다. 푸시 알림을 iOS로 보내는 역할을 담당한다.
* 애플 개발자 등록이 되어 있어야 사용 가능한 것으로 알고 있다.
* 아래 나오는 fcm 을 통해 통합하여 관리할 수 있는것으로 알고 있다.
- iOS 단말
안드로이드 푸시 알림
안드로이드 푸시 알람도 iOS 푸시 알림과 비슷한 절차로 진행된다.
APNS 대신 FCM(Firebase Cloud Messaging)을 사용한다는 점만 다르다.
SMS 메시지
SMS를 보낼 때는 보통 제 3사업자의 서비스(서드 파티)를 많이 사용한다.
책에서는 트윌리오, 넥스모 라는 서비스를 소개하였지만
국내에서는 NHN Cloud가 API 명세도 깔끔했고 실제 사용에서도 무난했다.
* 예전에 어떤 정부기관 프로젝트에 참여했을 때에는 아예 별도 구성된 솔루션을 사용한 경우도 있었다.
보내고 싶은 알림을 특정 DB Table에 insert 하면 (새로운 record가 있나 계속 체크하는 방식이였을 것 같다.) 그 내용대로 SMS 을 전송해주었다.
이메일
마찬가지로 제 3사업자의 서비스를 사용한다.
직접 구축해도 되지만 고려해야 할 것들이 많아진다.
책에서는 센드그리드, 메일침프 라는 서비스를 소개했다.
AWS 에서는 SES 라는 이름으로 서비스를 제공해준다.
전송 성공률과 데이버 분석 기능이 좋은 서비스를 사용하면 되겠다.
정리
연락처 정보 수집 절차
알림을 보내려면 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보가 필요하다.
사용자가 앱을 설치하거나 처음으로 계정을 등록 하면 API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장한다.
* 전화번호, 이메일 주소의 경우 개인정보 처리방침 작성도 고려해야 한다.
데이터 베이스 구조는 다음과 같이 설계할 수 있는데,
추가적으로 시간이 있다면 전화번호 / 이메일 주소가 제거 되었을 경우나, 기기 변경 / 앱 삭제 의 경우도 고려하면 좋을 것이다.
알림 전송 및 수신 절차
개략적 설계안 (초안)
- 각각의 서비스들은 마이크로서비스 일 수도 있고 크론잡일 수도 있고, 분산 시스템 컴포넌트일 수도 있다. ex. 납기일 안내, 배송 알림 등
- 알림 시스템은 우선 1개 서버만 사용하는 시스템으로 가정한다. 이 시스템은 서비스들에 알림 전송을 위한 API를 제공해야 하고, 제 3자 서비스(서드 파티 서비스)에 전달할 알림 요청을 만들어 낼 수 있어야 한다.
- 제 3자 서비스(서드 파티 서비스)는 사용자에게 알림을 실제로 전송하는 역할을 한다.
서드파티와의 통합을 진행할 때 유의할 것은 확장성이다. 쉽게 새로운 서비스를 통합하거나 기존 서비스를 제거할 수 있어야 한다.
또 글로벌 서비스일 경우 국가에 따른 지원 여부를 고려해야 한다. (책에서 든 예시는 FCM은 중국에서 사용 불가능 하기 때문에 제이푸시, 푸시와이 같은 서비스를 사용해야 한다고 한다.)
이 설계의 문제점은 SPOF와 알림 서비스가 한 대 이기 때문에 규모 확장성이 낮다는 것이다.
1개의 서버로 구성되어 있기 때문에 트래픽이 많이 몰리게 되면 성능 병목으로 인한 과부하도 있을 수 있다.
개략적 설계안 (개선된 버전)
알림 서버
알림 서버는 다음과 같은 기능을 제공한다.
- 알림 전송 API
스팸 방지를 위해 보통 사내 서비스 또는 인증된 클라이언트만 이용 가능하다.
- 알림 검증(validation)
이메일 주소, 전화번호 등에 대한 기본적 검증을 수행한다.
- 데이터베이스 또는 캐시 질의
알림에 포함시킬 데이터를 가져오는 기능
- 알림 전송
알림 데이터를 메시지 큐에 넣는다.
본 설계안은 하나 이상의 메시지 큐를 사용하므로 알림을 병렬적으로 처리할 수 있다.
하나의 메시지 큐는 하나의 노드(or pod)으로 구성되는건가?
캐시
사용자 정보, 단말 정보, 알림 템플릿 등을 캐시한다.
데이터 베이스
사용자, 알림, 설정 등 다양한 정보를 저장한다.
메시지 큐
시스템 컴포넌트 간 의존성을 제거하기 위해 사용. 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할도 한다. 본 설계안에서는 알림의 종류별로 별도 메시지 큐를 사요하였다. 따라서 제 3자 서비스 가운데 하나에 장애가 발생해도 다른 종류의 알림은 정상 동작하게 된다.
작업 서버
메시지 큐에서 전송할 알림을 꺼내서 서드 파티로 전달하는 역할을 담당
전송 플로우
1. API를 호출하여 알림 서버로 알림을 보낸다.
2. 알림 서버는 사용자 정보, 단말 토큰, 알림 설정 같은 메타데이터(metadata)를 캐시나 데이터베이스에서 가져온다.
3. 알림 서버는 전송할 알림에 맞는 이벤트를 만들어서 해당 이벤트를 위한 큐에 넣는다.
4. 작업 서버는 메시지 큐에서 알림 이벤트를 꺼낸다.
5. 작업 서버는 알림을 서드파티로 보낸다.
5. 서드파티는 사용자 단말로 알림을 전송한다.
3단계 상세 설계
안정성
데이터 손실 방지
알림 전송 시스템의 가장 중요한 요구사항 가운데 하나는 어떤 상황에서도 알림이 소실되면 안 된다는 것이다. 알림이 지연되거나 순서가 달라질 수는 있지만 사라지면 곤란하다.
이 요구사항을 만족하려면 알림 시스템은 알림 데이터를 데이터베이스에 보관하고 재시도 메커니즘을 구현해야 한다.
알림 로그 데이터베이스를 유지하는 것이 한 가지 방법이다.
알림 로그 DB는 nosql로 하면 좋지 않으려나 싶다.
알림 중복 전송 방지
같은 알림이 여러번 반복되는 것을 완전히 막는 것은 가능하지 않다.
( 참고 : https://bravenewgeek.com/you-cannot-have-exactly-once-delivery/ )
따라서 중복 탐지 메커니즘이 클라이언트 단에 있으면 좋다.
보내야 할 알림이 도착하면 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 살핀다. 중복된 이벤트라면 버리고, 그렇지 않으면 알림을 발송한다.
추가로 필요한 컴포넌트 및 고려사항
알림 템플릿
알림은 대부분 형식이 비슷하다. 이런 유사성을 고려하여 알림 메시지의 모든 부분을 처음부터 만들 필요가 없도록 한다. 알림 인자, 스타일, 추적 링크를 조정하기만 하면 필요한 알림을 만들어 낼 수 있도록 한다.
형식을 일관성 있게 유지할 수 있고, 오류 가능성 및 알림 작성에 드는 시간도 줄일 수 있다.
알림 설정
사용자는 이미 너무 많은 알림을 받고 있어서 쉽게 피곤함을 느낀다. 따라서 많은 서비스에서 사용자가 알림 설정을 상세히 조정할 수 있도록 하고 있다.
user_id | bigint | |
channel | varchar | 알림이 전송될 채널.푸시, 이메일, SMS 등 |
opt_in | boolean | 해당 채널로 알림을 받을 것인지의 여부 |
topic(주제) 별 알림 설정을 도입해도 좋을 것 같다.
전송률 제한
사용자에게 너무 많은 알림을 보내지 않도록 사용자가 받을 수 있는 알림의 빈도를 제한한다.
알림을 너무 많이 보내면 사용자가 알림 기능을 아예 꺼 버릴 수도 있다.
이렇게 할 경우 필수 알림과 광고성 알림 을 나누면 좋지 않을까 싶다.
재시도 방법
제 3자 서비스가 알림 전송에 실패하면 해당 알림을 재시도 전용 큐에 넣고 같은 문제가 계속해서 발생하면 개발자에게 통지한다.
우리 회사의 경우 slack을 통해서 알림이 오도록 처리했다.
푸시 알림과 보안
알림 전송 API는 appKey와 appSecret을 사용하여 보안을 유지한다.
큐 모니터링
알림 시스템의 중요한 메트릭 중 하나는 큐에 쌓인 알림의 개수이다.
이벤트 추적
알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 메트릭은 사용자를 이해하는데 중요하다.
* 책에서는 알림 수신 거부 설정 에 대한 메트릭도 고려하였다.
수정된 설계안
추가 된 것
- 알림 서버의 인증, 전송률 제한 기능
- 전송 실패 대응을 위한 재시도 기능. 실패한 알림은 다시 큐에 넣고 지정된 횟수만큼 재시도 한다.
- 전송 템플릿 기능
- 모니터링과 추적을 위한 분석 서비스
4단계 마무리
각 컴포넌트의 구현 방법과 최적화 기법에 대해서 심도있게 알아보았다.
이번 장에서는 아래 내용에 집중하였다.
- 안정성: 메시지 전송 실패율을 낮추기 위해 안정적인 재시도 메커니즘 도입
- 보안: 인증된 클라이언트만이 알림을 보낼 수 있도록 appKey, appSecret 등의 메커니즘 이용
- 이벤트 추적 및 모니터링
- 사용자 알림 수신 설정
- 전송률 제한
fin.