가상 면접 사례로 배우는 대규모 시스템 설계 기초 chapter 10. 알림 시스템 설계를 읽으면서 작성한 글 입니다
면접관 : 하루에 백만 건 이상의 알림을 처리하는 확장성 높은 시스템을 구축하려면 어떻게 해야할까요?
면접관이 다음과 같은 질문을 했다고 하자.
알림 시스템 설계 시 아래와 같은 내용을 고려할 수 있을 것이다. 이는 적절한 질문을 통해 요구사항이 무엇인지 지원자가 스스로 찾아가야 한다.
iOS 푸시 알림, 안드로이드 푸시 알림, SMS 메시지, 이메일을 지원하는 알림 시스템의 개략적 설계안을 살펴보자.
iOS, 안드로이드, SMS 메시지, 이메일의 알림 메커니즘이 어떻게 동작하는지 알아보자.
iOS에서 푸시 알림을 보내기 위해서는 세 가지 컴포넌트가 필요하다.
APNS 동작 방식에 대해 자세히 알고싶다면 여기를 참고하자.
안드로이드에서 푸시 알림을 보내기 위해서는 세 가지 컴포넌트가 필요하다.
FCM 동작 방식에 대해 자세히 알고싶다면 여기를 참고하자.
SMS 메시지를 보낼 때는 트윌리오, 넥스모 같은 제3사업자의 서비스를 많이 이용한다.
많은 회사가 상용 이메일 서비스를 이용한다. 센드그리드, 메일침프와 같은 서비스가 있다.
그렇다면 각 서비스는 알림을 보낼 단말을 어떻게 찾아서 알림을 보낼까? 알림을 보내려면 기기 단말 토큰, 전화번호, 이메일 등의 정보가 필요하다. 이 정보들은 사용자가 앱을 설치하거나, 처음으로 계정을 등록할 때 API서버에서 사용자의 정보를 수집하여 데이터베이스에 저장한다.
각각의 서비스, 1개의 서버를 사용하는 알림 시스템, 사용자에게 알림을 실제로 전달하는 제3자 제공 서비스를 아래와 같은 개략적 방식을 이용하여 설계할 수 있다.
그러나 이 설계에는 몇가지 문제가 있다.
초안의 문제점을 알았으니 다음과 같은 방향으로 개선을 해보면,
데이터베이스와 캐시를 알림 시스템의 주 서버에서 분리한다.
알림 서버를 증설하고 자동으로 수평적 규모 확장이 이루어질 수 있도록 한다.
메시지 큐를 이용해 시스템 컴포넌트 사이의 강한 결합을 끊는다.
각각의 서비스 : 알림 시스템 서버의 API를 통해 알림을 보낼 서비스이다.
알림 서버
캐시 : 사용자 정보, 단말 정보, 알림 템플릿 등을 캐시한다.
데이터 베이스 : 사용자, 알림, 설정 등 다양한 정보를 저장한다.
메시지 큐 : 시스템 컴포넌트 간 의존성을 제거하기 위해 사용한다. 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할도 한다.
작업 서버 : 메시지 큐에서 전송할 알림을 꺼내서 제3자 서비스로 전달하는 역할을 담당하는 서버이다.
지금까지 개략적 설계를 진행해봤다. 몇가지 사항을 더 고려하여 최종 설계안을 도출해보자.
알림 전송 시스템의 가장 중요한 요구사항 중 하나는 어떤 상황에서도 알림이 소실되면 안 된다는 것이다. (알림이 지연되거나 순서가 보장되지는 않아도 된다.)
같은 알림이 여러 번 반복되는 것을 완전히 막는 것은 가능하지 않다. 대부분 알림은 딱 한번 전송되지만 분산 시스템 특성상 가끔은 같은 알림이 중복되어 전송되기도 한다.
대형 알림 시스템은 하루에도 수백만 건 이상의 알림을 처리하고 대부분 알림 메시지 형식이 비슷하다. 알림 템플릿은 이런 유사성을 고려해 알림 메시지의 모든 부분을 처음부터 다시 만들 필요 없도록 해준다.
본문:
인기 상품 [item_name]이 재입고 되었습니다. 현재 잔여 수량은 [item_cnt] 입니다.
많은 웹사이트와 앱에서는 사용자가 알림 설정을 상세히 조정할 수 있도록 하고있다. 알림 설정 테이블에 보관되며 다음과 같은 필드들이 필요하다.
user
channel(알림이 전송될 채널, 푸시 알림, 이메일 등)
opt_in(해당 채널로 알림을 받을 것인지 여부)
한 사용자가 받을 수 있는 알림의 빈도를 제한하여 사용자에게 많은 알림을 보내지 않도록 할 수 있다. 이 기능이 중요한 이유로는, 알림을 너무 많이 보내면 사용자가 알림 기능을 아예 꺼 버릴 수 있기 때문이다.
제3자 서비스가 알림 전송에 실패하면 해당 알림을 재시도 전용 큐에 넣는다. (만약 같은 문제가 계속 발생하면 개발자에게 통지해야함)
iOS와 안드로이드 앱의 경우, 알림 전송 API는 appKey, appSecret을 사용하여 보안을 유지한다. 인증되었거나 승인된 클라이언트만 해당 API를 사용하여 알림을 보낼 수 있도록 한다.
지금까지 설명한 내용을 모두 반영하여 수정한 설계안이다.