📚 Study

[System Design] 10. 알림 시스템 설계

date
Jul 20, 2023
slug
book-system-design-interview-10
author
status
Public
category
📚 Study
tags
Book
Server
summary
메시지큐, 재시도 메커니즘, 큐 모니터링, 전송률 제한, 보안을 잊지 말 것!
type
Post
thumbnail
다운로드.png
notion image
📚
Alex Zu, <System Design Interview(가상 면접 사례로 배우는 대규모 시스템 설계 기초)>를 읽고 정리한 글입니다.
📝
목차
알림 시스템(notification system)을 설계해보자1단계 문제 이해 및 설계 범위 확정어떤 종류(모바일, 메시지, 이메일 등)의 알림을 지원해야 하는가?실시간 시스템(real-time)이어야 하는가?어떤 종류의 단말(iOS, 안드로이드, Desktop 등)을 지원해야 하는가?알림 수신에 대한 옵션 기능이 존재하는가?하루 몇 건의 알림을 보낼 수 있어야 하는가?2단계 개략적인 설계안 제시 및 동의 구하기1. 알림 유형별 지원 방안(iOS / 안드로이드 / SMS 메시지 / 이메일)2. 연락처 정보 수집 절차3. 알림 전송 및 수신 절차초안 설계 : 다음 4가지(서비스, 알림 시스템, 제3자 서비스, 단말) 노드가 필요하다.부족한 부분 : 서버 다중화, 데이터베이스/캐시 분리, 메시지큐 분리 필요!개선된 알림 시스템 개략적 설계도3단계 상세 설계안정성(reliability)을 위해 다음 2가지 항목을 고려해보자1) 데이터 손실 방지2) 알림 중복 전송 방지추가로 필요한 컴포넌트 및 고려사항들..알림 템플릿은 어떤 형태일까?사용자 알림 설정은 어떻게 저장할 것인가?전송률 제한을 고려할 것인가?알림 전송에 실패할 시, 재시도 메커니즘을 꾸릴 것인가?보안을 어떻게 유지할 것인가?큐 모니터링을 어떤 방식으로 할 것인가?이벤트 추적은 무엇을 통해 할 것인가?수정된 최종 설계안4단계 마무리알림 시스템을 구축할 때 체크리스트
 
 

알림 시스템(notification system)을 설계해보자

모바일 푸시 알림, SMS 메시지, 이메일로 구분되는 알림 시스템을 설계해보고, 알림 시스템에서 중요하게 생각해봐야 할 요소들을 생각해보자.
 

1단계 문제 이해 및 설계 범위 확정

어떤 종류(모바일, 메시지, 이메일 등)의 알림을 지원해야 하는가?

알림 시스템의 종류에 따라 시스템 구조와 필요 기술 스택이 달라지기 때문에 이 점을 확실히 하고 설계에 들어가야 한다.

실시간 시스템(real-time)이어야 하는가?

알림이 얼마나 빠르게 전달되어야 하는지, 요청이 몰려 서버에 높은 부하가 걸릴 경우 약간의 딜레이를 허용할 것인지 등 알림 시스템의 기초 성능 스펙을 확인해야 한다.

어떤 종류의 단말(iOS, 안드로이드, Desktop 등)을 지원해야 하는가?

알림의 종류와 마찬가지로 단말의 종류에 따라 필요한 알림제공자(provider)의 종류가 달라지기 때문에 필수로 확인해야 한다.

알림 수신에 대한 옵션 기능이 존재하는가?

사용자가 알림을 허용하지 않았을 때 알림을 받지 않도록 하는 기능이 구현되어야 하는지 확인해야 한다.

하루 몇 건의 알림을 보낼 수 있어야 하는가?

실시간으로 매우 많은 알림이 보내지는 만큼, 알림 시스템 서버는 방대한 알림의 양을 버틸 수 있어야 한다.
 

2단계 개략적인 설계안 제시 및 동의 구하기

알림 시스템의 개략적 설계안을 짜기 위해선, 다음 3가지 항목에 대한 고민이 필요하다.
💭
1️⃣ 알림 유형별 지원 방안
2️⃣ 연락처 정보 수집 절차
3️⃣ 알림 전송 및 수신 절차
 

1. 알림 유형별 지원 방안(iOS / 안드로이드 / SMS 메시지 / 이메일)

알림 유형별로 알림 서비스 유형이 달라진다.
  • iOS 푸시 알림
    • 알림 제공자APNSiOS 단말
    • 알림 제공자 : 단말 토큰(단말기 고유 식별자)과 페이로드(알림 내용)를 담은 알림을 APNS로 보냄
    • APNS : Apple Push Notification Service. 애플이 제공하는 원격 서비스로, 푸시 알림을 단말 기기로 전송한다.
  • 안드로이드 푸시 알림
    • 알림 제공자FCMiOS 단말
    • 전체적으로 iOS와 비슷하지만, APNS 대신 FCM(Firebase Cloud Messaging)을 사용한다.
  • SMS 메시지
    • 제3사업자(메시지 전송)의 서비스를 많이 사용한다.
  • 이메일
    • 회사 고유 이메일 서버를 구축하거나, 상용 이메일 서비스를 사용한다.
    • 데이터 분석 서비스를 제공하는 이메일 서비스도 있다.
 

2. 연락처 정보 수집 절차

알림을 보내기 위해 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보를 저장해두어야 한다.
이때, 한 사용자가 여러 단말을 가질 수 있고 알림은 모든 단말에 전송되어야 한다는 점을 기억하자.
회원가입 / 서비스 접속 등 어떠한 단계에서 어떠한 정보를 수집할 것인지 구상하자.
 

3. 알림 전송 및 수신 절차

전체적인 구성은 초안 설계로 그려보고, 개선된 설계를 보면서 디테일한 부분들은 점차로 디벨롭해보자.
1차 초안 설계
1차 초안 설계
2차 개선 설계
2차 개선 설계

초안 설계 : 다음 4가지(서비스, 알림 시스템, 제3자 서비스, 단말) 노드가 필요하다.

1차 초안 설계
1차 초안 설계
초안 설계에 필요한 노드는 다음 4가지이다.
  • 서비스 : 알림을 보내고자 하는 서비스
  • 알림 시스템 : 알림 전송/수신 처리의 핵심, 연결된 서비스들이 사용할 수 있는 알림 API를 제공해야 하고, 제3자 서비스에 전달할 알림 페이로드(payload)를 만들 수 있어야 한다.
  • 제3자 서비스 : 사용자에게 알림을 실제로 전달하는 역할, 확장성(extensibility)을 고려하여, 쉽게 새로운 서비스를 통합하거나 기존 서비스를 제거할 수 있어야 한다.
  • 단말 : 사용자가 알림을 수신할 단말
 

부족한 부분 : 서버 다중화, 데이터베이스/캐시 분리, 메시지큐 분리 필요!

  • SPOF(Single Point Of Failure) : 알림 서비스에 서버가 하나밖에 없으므로, 그 서버에 장애가 생기면 전체 서비스의 장애로 이어진다. ⇒ 서버 다중화 필요! 컴포넌트간 결합 느슨히!
  • 규모 확장성 : 한 대의 서비스로 푸시 알림에 관계된 모든 것을 처리하므로, 데이터베이스나 캐시 등 중요 컴포넌트의 규모를 개별적으로 확장할 수 있는 방법이 없다. ⇒ 데이터베이스, 캐시 분리!
  • 성능 병목 : 모든 것을 한 서버로 처리하면 사용자 트래픽이 많이 몰리는 시간에는 시스템이 과부하 상태에 빠질 수 있다. ⇒ 서버 다중화 필요!
 

개선된 알림 시스템 개략적 설계도

2차 개선 설계
2차 개선 설계
  • 부족한 부분 개선
    • 데이터베이스캐시를 알림 시스템의 주 서버에서 분리한다.
    • 알림 서버를 증설하고 자동으로 수평적 규모 확장이 이루어질 수 있도록 한다.
    • 메시지 큐를 이용해 시스템 컴포넌트 사이의 강한 결합을 끊는다.
  • 알림 서버의 기능 디벨롭
    • 알림 전송 API : 스팸 방지를 위하여 보통 사내 서비스 또는 인증된 클라이언트만 이용 가능하도록 한다.
    • 알림 검증(validation) : 이메일 주소, 전화번호 등에 대한 기본적 검증 수행
    • 데이터베이스 또는 캐시 질의 : 알림에 포함시킬 데이터 쿼리 질의
    • 알림 전송 : 알림 데이터를 메시지 큐에 넣기. 하나 이상의 메시지 큐를 사용하므로 알림을 병렬적으로 처리할 수 있다.
  • 그 외 기능 디벨롭
    • 캐시 : 사용자 정보, 단말 정보, 알림 템플릿(template) 등을 캐시
    • 데이터베이스 : 사용자 정보, 단말 정보, 알림 템플릿 등 정보 저장
    • 메시지 큐 : 시스템 컴포넌트 간 의존성을 제거하기 위해 사용. 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할. 알림 종류 별로 각각의 메시지큐를 두어, 제3자 서비스 가운데 하나가 장애가 발생해도 다른 종류의 알림은 정상 동작하도록 함.
    • 작업 서버 : 메시지 큐에서 전송할 알림을 꺼내서 제3자 서비스로 전달
 

3단계 상세 설계

가장 기본적인 기능(알림 전송 기능)을 위한 설계가 완료되었으니, 이제 다음 항목에 대한 고민을 해보자.
✔️
상세 설계를 위한 고민
  • 안정성(reliability)
  • 추가로 필요한 컴포넌트 및 고려사항
    • 알림 템플릿, 알림 설정
    • 전송률 제한
    • 재시도 메커니즘
    • 보안
    • 큐에 보관된 알림에 대한 모니터링
    • 이벤트 추적 등

안정성(reliability)을 위해 다음 2가지 항목을 고려해보자

분산 환경에서 운영될 알림 시스템을 설계할 때는 안정성을 확보하기 위한 사항 몇 가지를 반드시 고려해야 한다.

1) 데이터 손실 방지

어떠한 상황에서도 알림이 소실되면 안된다. 알림이 지연되거나 순서가 뒤바뀌는 것은 괜찮지만, 사라지면 매우매우 곤란하다! 이 요구사항을 만족하기 위해선 알림 데이터를 데이터베이스에 보관한 후, 재시도 메커니즘을 구현해야 한다. 이를 위해 알림 로그만 따로 모아두는 데이터베이스를 구축하는 것이 한 가지 방법이다.

2) 알림 중복 전송 방지

같은 알림이 여러 번 반복되는 것을 완전히 막는 것은 불가능하다. 분산 시스템의 특성상 가끔은 같은 알림이 중복되어 전송되기도 할 것이다. 그 빈도를 줄이기 위해선 중복을 탐지하는 메커니즘을 도입하고, 오류를 신중하게 처리해야 한다.
  • 보내야 할 알림이 도착하면 그 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 살핀다. 중복된 이벤트라면 버리고, 그렇지 않으면 알림을 발송한다.

추가로 필요한 컴포넌트 및 고려사항들..

알림 템플릿은 어떤 형태일까?

알림 템플릿은 각 알림 메시지들의 유사성을 고려하여, 알림 메시지의 모든 부분을 처음부터 다시 만들 필요가 없게 해 준다. 아래는 간단한 예제다.
본문: 여러분이 꿈꿔온 상품을 우리가 준비했습니다. [item_name]이 다시 입고되었습니다. [date]까지만 주문이 가능합니다! 타이틀: 지금 바로 [item_name]을 주문하세요!

사용자 알림 설정은 어떻게 저장할 것인가?

사용자는 이미 너무 많은 알림을 받고 있어서 쉽게 피곤함을 느낀다. 따라서 많은 웹사이트와 앱에서는 사용자가 알림 설정을 상세히 조정할 수 있도록 하고 있다. 해당 정보는 알림 설정 테이블에 보관되며, 이 테이블에는 아마 다음과 같은 필드들이 필요할 것이다.
user_id : bigint channel : varchar // 알림이 전송될 채널. 푸시 알림, 이메일, SMS 등 opt_in : boolean // 해당 채널로 알림을 받을 것인지 여부
이와 같은 설정을 도입한 후에는 특정 종류의 알림을 보내기 전에 반드시 해당 사용자가 해당 알림을 켜 두었는지 확인해야 한다.

전송률 제한을 고려할 것인가?

사용자에게 너무 많은 알림을 보내지 않도록 하는 방법 중 하나는, 한 사용자가 받을 수 있는 알림의 빈도를 제한하는 것이다. 이것이 중요한 이유는, 알림을 너무 많이 보내기 시작하면 사용자가 알림 기능을 아예 꺼 버릴 수도 있기 때문이다.
  • Q. 그러나 이 항목은, 위의 ‘알림 데이터 손실 방지’ 항목과 충돌되는 것 아닌가? 사용자가 받는 알림이 너무 많아서 임의로 제한해버리면, 알림 데이터가 손실되는 것과 같은 맥락 아닌가..? 흠,,

알림 전송에 실패할 시, 재시도 메커니즘을 꾸릴 것인가?

제3자 서비스가 알림 전송에 실패하면, 해당 알림을 재시도 전용 큐에 넣고 다시 시도한다.
같은 문제가 계속해서 발생하면 개발자에게 통지하도록 한다.

보안을 어떻게 유지할 것인가?

iOS와 안드로이드 앱의 경우 ,알림 전송 API는 appKey와 appSecret을 사용하여 보안을 유지한다. 따라서 인증된(authenticated) 혹은 승인된(verified) 클라이언트만 해당 API를 사용하여 알림을 보낼 수 있다.

큐 모니터링을 어떤 방식으로 할 것인가?

알림 시스템을 모니터링 할 때 중요한 메트릭(metric) 중 하나는 큐에 쌓인 알림의 개수이다. 이 수가 너무 크면, 작업 서버들이 이벤트를 빠르게 처리하지 못하고 있다는 뜻이다. 그런 경우, 작업 서버를 증설하는 것이 바람직하다.

이벤트 추적은 무엇을 통해 할 것인가?

알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 등의 메트릭은 사용자를 이해하는 데에 매우 중요하다. 데이터 분석 서비스(analytics)는 보통 이벤트 추적 기능도 제공한다. 따라서 보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합해야 한다.
graph LR ST([시작]) --> A[발송대기] A-->B[알림 발송] A-->C[오류] B-->C[오류] B-->D[사용자 수신] D-->E[클릭] D-->F[알림 수신 거부 설정]
 

수정된 최종 설계안

notion image
notion image
  • 알림 서버에 인증(authentication)전송률 제한(rate-limiting) 기능이 추가되었다.
  • 전송 실패에 대응하기 위한 재시도 기능이 추가되었다. 전송에 실패한 알림은 다시 큐에 넣고, 지정된 횟수만큼 재시도한다.
  • 전송 템플릿을 사용하여 알림 생성 과정을 단순화하고 알림 내용의 일관성을 유지한다.
  • 모니터링과 추적 시스템을 추가하여 시스템 상태를 확인하고 추후 시스템을 개선하기 쉽게 하였다.
 

4단계 마무리

알림 시스템을 구축할 때 체크리스트

다양한 방식) 규모 확장이 쉬울 뿐만 아니라 푸시 알림, SMS 메시지, 이메일 등 다양한 정보 전달 방식을 지원하는 알림 시스템을 구축하라.
컴포넌트 간 결합도) 시스템 컴포넌트 사이의 결합도를 낮추기 위해 메시지 큐를 적극적으로 사용하라.
안정성) 메시지 전송 실패율을 낮추기 위해 안정적인 재시도 메커니즘을 도입하라.
보안) 인증된 클라이언트만이 알림을 보낼 수 있도록 appKey, appSecret 등의 메커니즘을 이용하라.
모니터링) 알림이 성공적으로 전송되기까지의 과정을 추적하고, 알림 전송의 각 단계마다 이벤트를 추적하고 모니터링하라.
사용자 설정) 사용자가 알림 수신 설정을 조정할 수 있도록 하였다면, 알림을 보내기 전 해당 설정을 반드시 확인하도록 설계하라.
전송률 제한) 사용자에게 알림을 보내는 빈도를 제한하라.
 
 
 
다음 화 예고…
💡
페이스북, 인스타, 트위터 등의 뉴스 피드 시스템을 설계해보자!!