포스팅에 사용된 그림은 책에서 제공하는 그림들 입니다.
알림시스템은 최근 많은 프로그램이 채택한 인기 있는 기능이다.
이 기능을 갖춘 애플리케이션은 최신 뉴스, 제품 업데이트, 이벤트, 선물 등 고객에게 중요할 만한 정보를 비동기적으로 제공한다.
알림 시스템은 단순히 모바일 푸시 알림에 한정되지 않는다. 시스템은 모바일 푸시 알림, SMS 메시지, 그리고 이메일의 세 가지로 분류할 수 있다.
하루에 백만 건 이상의 알림을 처리하는 확장성 높은 시스템을 구축하는게 쉬운 과제는 아니다. 알림 시스템이 어떻게 구현되는지에 대한 깊은 이해가 필요한 작업이다. 아래 상황으로, 요구사항의 범위를 좁혀보자.
알림 시스템
이번 절에서는 IOS 푸시 알림, 안드로이드 푸시 알림, SMS 메시지, 그리고 이메일을 지원하는 시스템의 개략적인 설계안을 살펴보자.
각각의 알림 메커니즘이 어떻게 동작하는지 살펴보자.
iOS에서 푸시 알림을 보내기 위해서는 세 가지 컴포넌트가 필요하다.
{
"apps": {
"alert": {
"title": "Game Request",
"body": "Bob wants to play chess",
"action-loc-key":"PLAY"
},
"badge":5
}
}
안드로이드 푸시 알림도 비슷한 절차다. APNS대신 FCM(Firebase Cloud Messaging)을 사용하는 점만 다르다.
SMS 메시지를 보낼 때는 보통 트윌리오, 넥스모 같은 제 3사업자의 서비스를 많이 이용한다. 이런 서비스는 대부분 상용 서비스라서 이용 요금을 내야 한다.
대부분의 회사는 고유 이메일 서버를 구축할 역량은 갖추고 있다. 그럼에도 많은 회사가 상용 이메일 서비스를 이용한다. 그중 유명한 서비스로 샌드그리드, 메일침프가 있다. 전송 성공률도 높고, 데이터 분석 서비스도 제공한다.
알림을 보내려면 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보가 필요하다. 아래 그림과 같이 사용자가 우리 앱을 설치하거나 처음으로 계정을 등록하면 API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장한다.
이 데이터베이스에 연락처 정보를 저장할 테이블 구조는 아래그림과 같다. 필수 정보만 담은 개략적인 설계안으로, 이메일 주소와 전화번호는 user테이블에 저장하고, 단말 토큰은 device 테이블에 저장한다. 한 사용자가 여러 단말을 가질 수 있고, 알림은 모든 단말에 전송되어야 한다는 점을 고려한다.
우선 개략적인 설계안부터 살펴보고, 점차로 최적화해 나가도록 할 것이다.
아래 그림은 개략적 설계 초안이다. 각 시스템 컴포넌트에 대한 설명은 그 아래에 두었다.
이 설계에는 아래와 같은 문제가 있다.
초안의 문제점을 알아보았으니, 다음과 같은 방향으로 개선해보자.
위를 적용한 아래 설계안을 봐보자.
다음은 이메일 형태의 알림을 보내는 데 사용하는 API 예제다.
POST https://api.example.com/v/sms/send
API 호출 시 전송할 데이터(body)의 사례.
{
"to": [
{
"user id": 123456
}
],
"from": {
"email": "from_address@example.com"
},
"subject": "Hello, World!",
"content": [
{
"type": "text/plain",
"value": "Hello, World!"
}
]
}
이 컴포넌트들이 어떻게 협력하여 알림을 전송하는지 순서을 알아보자.
지금까지 개략적 설계를 진행하면서 알림의 종류, 연락처 정보 수집 절차, 그리고 알림 전송/수신 절차에 대해 살펴보았다. 아래 내용들을 좀 더 자세히 알아보자.
분산 환경에서 운영될 알림 시스템을 설계할 때는 안정성을 확보하기 위한 사항 몇 가지를 반드시 고려해야 한다.
알림 전송 시스템의 가장 중요한 요구사항 가운데 하나는 어떤 상황에서도 알림이 소실되면 안 된다는 것이다. 알림이 지연되거나 순서가 틀려도 괜찮지만, 사라지면 곤란하다는 것이다. 이 요구사항을 만족하려면 알림 데이터를 데이터베이스에 보관하고 재시도 매커니즘을 구현해야한다.
같은 알림이 여러번 반복되는 것을 완전히 막는 것은 가능하지 않다. 대부분의 경우 딱 한번만 전송되겠지만, 분산 시스템의 특성상 가끔은 알림이 중복되어 전송되기도 할 것이다. 그 빈도를 줄이려면 중복을 탐지하는 매커니즘을 도입하고, 오류를 신중하게 처리해야 한다.
지금까지 연락처 정보를 어떻게 수집하고, 알림은 어떻게 보내고 등을 알아보았는데, 알림 시스템은 사실 이보다 훨씬 복잡하다. 지금부터는 알림 템플릿, 알림 설정, 이벤트 추적, 시스템 모니터링, 처리율 제한 등 알림 시스템 구현을 위해 필요한 추가 컴포넌트들에 대해 알아보자.
대형 알림 시스템은 하루에도 수백만 건 이상의 알림을 처리한다. 그런데 그 알림 메시지 대부분은 형식이 비슷하다. 알림 템플릿은 이런 유사성을 고려하여, 알림 메시지의 모든 부분을 처믑퉈 다시 만들 필요 없도록 해 준다. 알림 템플릿은 인자나 스타일, 추적 링크를 조정하기만 하면 사전에 형식에 맞춰 알람을 만들어 내는 틀이다.
템플릿을 사용하면 전송될 알림들의 형식을 일관성 있게 유지할 수 있고, 오류 가능성뿐 아니라 알림 작성에 드는 시간도 줄일 수 있다.
사용자가 알림 설정을 상세히 조정할 수 있도록 해야한다. 이 정보는 알림 설정 테이블에 보관되며, 이 테이블에는 아마 아래와 같은 필드가 존재할 것이다.
user_id | bigInt |
---|---|
channel | varchar |
opt_in | boolean |
이와 같은 설정을 도입한 뒤에는 특정 종류의 알림을 보내기 전에 반드시 해당 사용자가 해당 알림을 켜 두었는지 확인해야 한다.
사용자에게 너무 많은 알림을 보내지 않도록 하는 방법은, 사용자가 받을 수 있는 알림의 빈도를 제한하는 것이다. 알림을 너무 많이 보내기 시작하면 사용자가 알림 기능을 아예 꺼버릴 수 도 있기 때문이다.
제3자 서비스가 알림 전송에 실패하면, 해당 알림을 재시도 전용 큐에 넣는다. 같은 문제가 계속해서 발생하면 개발자에게 통지한다(alert).
iOS와 안드로이드 앱의 경우, 알림 전송 API는 apikey와 appSecret을 사용하여 보안을 유지한다. 따라서 인증된, 혹은 승인된 클라이언트만 해당 API를 사용하여 알림을 보낼 수 있다.
알림 시스템을 모니터링 할 때 중요한 메트릭 하나는 큐에 쌓인 알림의 개수이다. 이 수가 너무 크면 작업 서버들이 이벤트를 빠르게 처리하고 있지 못하다는 뜻이다. 그런 경우에는 작업 서버를 증설하는 게 바람직할 것이다.
알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 케트릭은 사용자를 이해하는데 중요하다. 데이터 분석 서비스는 보통 이벤트 추적 기능도 제공한다. 데이터 분석 서비스는 보통 이벤트 추적 기능도 제공한다. 따라서 보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합해야만 한다.
위에 추가로 필요한 컴포넌트 및 고려사항을 모두 반영한 설계안은 아래 그림과 같다.
종전 설계안에 없던 많은 컴포넌트가 추가된 것을 확인할 수 있다.
알림은 중요 정보를 계속 알려준다는 점에서 필요불가결한 기능이다.
이번 장에서는 규모 확장이 쉬울 뿐 아니라 푸시 알림, SMS 메시지, 이메일 등 다양한 정보 전달 방식을 지원하는 알림 시스템을 만들어 보았다. 시스템 컴포넌트 사이의 결합도를 낮추기 위해 메시지 큐를 적극적으로 사용하였다.
개략적 설계안과 더불어 각 컴포넌트의 구현 방법과 최적화 기법에 대해서도 심도 있게 알아보았다.