가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고
가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설
product.kyobobook.co.kr
10장, 알림 시스템 설계
- 알림 시스템 (Notification System)은 최근 많은 프로그램이 채택한 인기 있는 기능
- 알림 시스템을 통해 최신 뉴스, 제품 업데이트, 이벤트, 선물 등 고객에게 중요할 만한 정보를 비동기적으로 제공한다.
- 단순히 모바일 푸시 알림에 한정되지 않는다.
- 알림 시스템의 종류
- 모바일 푸시 알림
- SMS 메시지
- 이메일
- 문제 이해 및 설계 범위 확정
- 하루에 백만 건 이상의 알림을 처리하는 확장성 높은 시스템을 구축하는 건 어렵다.
- 알림 시스템이 어떻게 구현되는지에 대한 깊은 이해가 필요
- 적절한 질문을 통해 요구 사항이 무엇인지 지원자 스스로 알아내야 한다.
- 질의응답
- 어떤 종류의 알림을 지원하는가?
- 푸시 알림, SMS 메시지, 이메일
- 실시간 시스템이어야 하는가?
- 연성 실시간 시스템 (Soft Real-Time)
- 알림은 가능한 빨리 전달되어야 하지만 시스템에 높은 부하가 걸렸을 때 약간의 지연은 무방
- 어떤 종류의 단말을 지원해야 하는가?
- iOS 단말, 안드로이드 단말, 랩톱/데스크톱
- 사용자에게 보낼 단말은 누가 만들 수 있는가?
- 클라이언트 애플리케이션 프로그램, 서버 측 스케쥴링
- 사용자가 알림을 받지 않도록 설정할 수 있는가?
- 그렇다. 해당 설정을 마친 사용자는 더 이상 알림을 받지 않아야 한다.
- 하루에 몇 건의 알림을 보낼 수 있어야 하는가?
- 천만 건의 모바일 푸시 알림, 백만 건의 SMS 메시지, 5백만 건의 이메일
- 어떤 종류의 알림을 지원하는가?
- 개략적 설계안 제시 및 동의 구하기
- 알림 유형별 지원 방안
- iOS 푸시 알림
- 알림 제공자 (Provider)
- 알림 요청을 만들어 애플 푸시 알림 서비스 APNS로 보내는 주체
- 알림 요청을 만들려면 다음과 같은 데이터가 필요하다
- 단말 토큰 (Device Token)
- 알림 요청을 보내는 데 필요한 고유 식별자
- 페이로드 (Payload)
- 알림 내용을 담은 JSON 딕셔너리
- 단말 토큰 (Device Token)
- APNS (Apple Push Notification Service)
- 애플이 제공하는 원격 서비스
- 푸시 알림을 iOS 장치로 보내는 역할
- iOS 단말
- 푸시 알림을 수신하는 사용자 단말
- 알림 제공자 (Provider)
- 안드로이드 푸시 알림
- iOS와 비슷한 절차
- APNS 대신 FCM(Firebase Cloud Messaging)을 사용
- SMS 메시지
- 트윌리오(Twilio), 넥스모(Nexmo)와 같은 서드파티 서비스를 이용
- 대부분 상용 서비스로, 이용요금을 내야 함.
- 이메일
- 대부분 회사는 고유 이메일 서버를 구축할 역량은 갖추고 있다.
- 그럼에도 많은 회사가 상용 이메일 서비스를 이용
- 대표적으로 샌드그리드 (Sendgrid), 메일침프 (Mailchimp)가 있다.
- 전송 성공률도 높고, 데이터 분석 서비스도 제공한다.
- iOS 푸시 알림
- 연락처 정보 수집 절차
- 알림을 보내려면 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보가 필요
- 사용자가 우리 앱을 설치하거나 처음으로 계정을 등록하면 API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장한다.
- 개략적 설계안 (초안)
- 1 부터 N 까지의 서비스
- 이 서비스 각각은 마이크로서비스일 수도 있고, 크론잡일 수도 있고, 분산 시스템 컴포넌트일 수도 있다.
- 사용자에게 납기일을 알리고자 하는 과금 서비스, 배송 알림을 보내려는 쇼핑몰 웹사이트 등이 그 예다.
- 알림 시스템
- 알림 전송/수신 처리의 핵심
- 우선 1개 서버만 사용하는 시스템으로 가정
- 이 시스템은 서비스 1-N에 알림 전송을 위한 API를 제공해야 하고, 서드파티 서비스에 전달할 알림 페이로드(Payload)를 만들어 낼 수 있어야 한다.
- 제 3자 서비스 (서드 파티 서비스)
- 사용자에게 알림을 실제로 전달하는 역할
- 확장성을 유의해야 한다.
- 쉽게 새로운 서비스를 통합하거나 기존 서비스를 제거할 수 있어야 한다.
- 가령 FCM은 중국에서는 사용할 수 없고, 중국 시장에서는 JPush, PushY 같은 서비스를 이용해야 한다.
- iOS, 안드로이드, SMS, 이메일 단말
- 사용자는 자기 단말에서 알림을 수신한다.
- 위 설계에는 몇 가지 문제가 존재한다.
- SPOF (Single-Point-Of-Failure)
- 알림 서비스에 서버가 하나 밖에 없다는 것은 그 서버에 장애가 생기면 전체 서비스의 장애로 이어진다는 뜻
- 규모 확장성
- 한 대 서비스로 푸시 알림에 관계된 모든 것을 처리하므로, 데이터베이스나 캐시 등 중요 컴포넌트의 규모를 개별적으로 늘릴 방법이 없다.
- 성능 병목
- 알림을 처리하고 보내는 것은 자원을 많이 필요로 하는 작업일 수 잇다.
- 모든 것을 한 서버로 처리하면 사용자 트래픽이 많이 몰리는 시간에는 시스템 과부하 상태에 빠질 수 있다.
- SPOF (Single-Point-Of-Failure)
- 1 부터 N 까지의 서비스
- 개략적 설계안 (개선 버전)
- 데이터 베이스와 캐시를 알림 시스템의 주 서버에서 분리
- 알림 서버를 증설하고 오토 스케일링이 이루어질 수 있도록 설계
- 메시지 큐를 이용해 시스템 컴포넌트 사이의 강한 결합을 끊기
- 알림 서버
- 알림 전송 API
- 스팸 방지를 위해 사내 서비스 또는 인증된 클라이언트만 이용
- 알림 검증
- 이메일 주소, 전화번호 등에 대한 기본적 검증
- 데이터베이스 또는 캐시 질의
- 알림에 포함시킬 데이터를 가져오는 기능
- 알림 전송
- 알림 데이터를 메시지 큐에 넣는다.
- 알림 전송 API
- 캐시
- 사용자 정보, 단말 정보, 알림 템플릿 등을 캐시
- 데이터베이스
- 사용자, 알림, 설정 등 다양한 정보를 저장
- 메시지 큐
- 시스템 컴포넌트 간 의존성을 제거하기 위해 사용
- 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할
- 알림의 종류별로 별도 메시지 큐를 사용하여 SPOF 제거
- 작업 서버
- 메시지 큐에서 전송할 알림을 꺼내 서드 파티 서비스로 전달
- 서드 파티 서비스
- iOS, 안드로이드 SMS, 이메일 단말
- 개략적 설계안 (개선 버전)의 작동 순서
- API를 호출하여 알림 서버로 알림을 보냄
- 알림 서버는 사용자 정보, 단말 토큰, 알림 설정 같은 메타데이터를 캐시나 데이터베이스에서 가져옴
- 알림 서버는 전송할 알림에 맞는 이벤트를 만들어서 해당 이벤트를 위한 큐에 넣음.
- 작업 서버는 메시지 큐에서 알림 이벤트를 꺼냄
- 작업 서버는 알림을 서드 파티 서비스로 보냄
- 서드 파티 서비스는 사용자 단말로 알림을 전송
- 알림 유형별 지원 방안
- 상세 설계
- 안정성
- 분산 환경에서 운영될 알림 시스템을 설계할 때는 안정성을 확보하기 위한 사항 몇 가지를 고려해야만 한다.
- 데이터 손실 방지
- 어떤 상황에서도 알림이 소실되면 안된다.
- 알림이 지연되거나 순서가 틀려도 괜찮지만, 사라지면 곤란하다.
- 알림 시스템은 알림 데이터를 데이터베이스에 보관하고, 재시도 매커니즘을 구현해야 한다.
- 알림 중복 전송 방지
- 중복을 탐지하는 매커니즘을 도입하고, 오류를 신중하게 처리
- 보내야 할 알림이 도착하면 그 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 살핀다. 중복된 이벤트라면 버리고, 그렇지 않으면 알림을 발송한다.
- 추가로 필요한 컴포넌트 및 고려 사항
- 알림 템플릿
- 대형 알림 시스템은 하루에도 수백만 건 이상의 알림을 처리한다.
- 대부분 비슷한 형식의 알림을 전송하는데, 이런 유사성을 고려하여 알림 메시지의 모든 부분을 처음부터 다시 만들 필요 없이 해준다.
- 알림 템플릿은 인자나 스타일, 추적 링크를 조정하기만 하면 사전에 저장한 형식에 맞추어 알람을 만들어내는 틀이다.
- 템플릿을 사용하면 전송될 알림들의 형식을 일관성 있게 유지할 수 있고, 오류 가능성 뿐만 아니라 알림 작성에 드는 시간도 줄일 수 있다.
- 알림 설정
- 사용자는 이미 너무 많은 알림을 받고 있어 쉽게 피곤함을 느낀다.
- 많은 웹사이트와 앱에서는 사용자가 알림 설정을 상세히 조정할 수 있도록 하고 있다.
- 전송률 제한
- 사용자에게 너무 많은 알림을 보내지 않도록 한 사용자가 받을 수 있는 알림의 빈도를 제한
- 알림을 너무 많이 보내기 시작하면 사용자가 알림을 꺼버릴 수도 있기 때문
- 재시도 매커니즘
- 서드 파티 서비스가 알림 전송에 실패하면, 해당 알림을 재시도 전용 큐에 넣는다.
- 같은 문제가 지속 발생하면 서드 파티 개발자에게 통지한다 (Alert)
- 푸시 알림과 보안
- iOS와 안드로이드 앱의 경우 알림 전송 API는 appKey와 AppSecret을 사용하여 보안을 유지
- 따라서 인증된/승인된 (Authenticated/Verified) 클라이언트만 해당 API를 사용하여 알림을 보낼 수 있다.
- 큐에 보관된 알림에 대한 모니터링과 이벤트 추적
- 알림 시스템을 모니터링 할 때 중요한 메트릭 하나는 큐에 쌓인 알림의 개수이다.
- 이 수가 너무 크면 작업 서버들이 이벤트를 빠르게 처리하고 있지 못하다는 뜻이다.
- 그런 경우에는 작업 서버를 증설하는 게 바람직할 것이다.
- 이벤트 추적
- 알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 메트릭은 사용자를 이해하는데 중요하다.
- 데이터 분석 서비스는 보통 이벤트 추적 기능도 제공한다.
- 따라서 보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합해야만 한다.
- 알림 템플릿
- 개선된 설계안
- 알림 서버에 인증과 전송률 제한 기능 추가
- 전송 실패에 대응하기 위한 재시도 기능 추가
- 전송 템플릿을 사용하여 생성 과정을 단순화하고 내용의 일관성을 유지
- 모니터링과 추적 시스템을 추가하여 시스템 상태를 확인하고 추후 시스템을 개선하기 쉽게 함
- 안정성
- 마무리
- 알림은 중요 정보를 계속 알려준다는 점에서 필요불가결한 기능
- 이번 장에서 우리는 규모 확장이 쉬울 뿐 아니라 푸시 알림, SMS 메시지, 이메일 등 다양한 정보 전달 방식을 지원하는 알림 시스템을 만들어 보았다.
- 시스템 컴포넌트 사이의 결합도를 낮추기 위해 메시지 큐를 적극적으로 사용
- 개략적 설계안과 더불어 각 컴포넌트의 구현 방법과 최적화 기법에 대해서도 심도 있게 알아보았다.
- 안정성, 보안, 이벤트 추적 및 모니터링, 사용자 설정, 전송률 제한
- 느낀 점
- 대규모 알림 시스템을 책을 읽으며 함께 설계하고, 구상해보았다.
- SPOF를 예상하여 단일 알림 서버를 피하고 데이터베이스와 캐시를 붙여 API 요청시 자주 Read되는 사용자 정보를 제공하는 것 까지는 예상했으나 알림 서버와 작업 서버를 구분하고, 그 사이에 메시지 큐를 두어 누락 없는 순차적 메시지 발송과 오류시 재시도 기능을 추가한 것을 보았을때 환희에 차 올랐다. 뭐랄까, 조금씩 안 맞는 퍼즐들이 한 번에 맞춰진 느낌이랄까?
- 대규모 시스템을 설계하는 과정은 분명히 어렵고, 완벽할 수 없다. 완벽을 꿈꾸며 수 많은 오류의 강을 헤쳐나가며 우리는 많은 난관을 경험하고, 나아간다.
- 분산 시스템, 마이크로 서비스 아키텍처, SPOF 개선, 오류 시 재시도, 인증/인가 권한 확인, 캐시, 데이터베이스 샤딩.. 기술은 완벽을 향해 한 걸음 한 걸음 나아가고 있다.
- 나는 어떤 기술을 통해, 어떤 완벽을 만들 것인가?
- 나는 개발자로서 사용자에게 어떤 완벽함을 선사할 것인가?
- 우리는 누군가에게 완벽한 존재일 수 있는가?
- …
'개발 이야기 (Dev Story)' 카테고리의 다른 글
"가상 면접 사례로 배우는 대규모 시스템 설계 기초"를 읽고 - 11장 (0) | 2024.05.11 |
---|---|
"가상 면접 사례로 배우는 대규모 시스템 설계 기초"를 읽고 - 7장 (0) | 2024.05.11 |
"가상 면접 사례로 배우는 대규모 시스템 설계 기초"를 읽고 - 6장 (0) | 2024.05.11 |
"가상 면접 사례로 배우는 대규모 시스템 설계 기초"를 읽고 - 4장 (0) | 2024.05.11 |
[아키텍처 패턴] 레이어 패턴 (Layered Pattern) (0) | 2024.05.10 |