[대규모 시스템 설계 스터디] 10장 정리

김연준·2026년 8월 13일
post-thumbnail

알림 시스템 설계

알림 시스템은 사용자에게 중요한 정보나 이벤트를 전달하는 시스템

대표적인 알림 방식은 다음과 같음.

  • 모바일 푸시 알림
  • SMS 메시지
  • 이메일

알림 시스템은 보통 정해진 시간 안에 빠르게 전달되는 것이 중요하지만, 일부 지연이 발생했다고 시스템 전체가 실패한 것으로 보지는 않기 때문에 연성 실시간(Soft Real-Time) 시스템에 가까움.

반대로 경성 실시간(Hard Real-Time) 시스템은 정해진 deadline을 반드시 지켜야 하며 이를 넘기는 것이 시스템 실패로 이어질 수 있음.


1. 요구사항 확인

알림 시스템을 설계하기 전에 다음 사항을 먼저 확인해야 함.

  • 어떤 종류의 알림을 지원할 것인가

    • 푸시
    • SMS
    • 이메일
  • 어떤 종류의 단말을 지원할 것인가

    • iOS
    • Android
    • 웹 등
  • 알림을 생성하는 주체는 누구인가

  • 사용자가 특정 알림을 거부하거나 opt-out 할 수 있어야 하는가

  • 하루에 몇 건의 알림을 처리해야 하는가

  • 어느 정도의 알림 지연까지 허용할 것인가


2. 알림 유형별 전송 방식

iOS 푸시 알림

iOS에 푸시 알림을 보내기 위해서는 크게 다음 세 요소가 필요함.

알림 제공자(Notification Provider)

알림 요청을 생성하여 APNs로 전달하는 서버임.

알림을 생성하기 위해 다음과 같은 정보가 필요함.

  • Device Token

    • 특정 기기에서 실행되는 특정 앱으로 푸시 알림을 전달하기 위해 APNs가 발급하는 식별 정보
    • 앱은 발급받은 Device Token을 알림 서버에 전달
  • Payload

    • 알림 내용을 담고 있는 JSON 데이터

APNs

Apple Push Notification service

Apple이 제공하는 푸시 알림 서비스로, 알림 서버에서 받은 요청을 실제 iOS 단말로 전달함.

알림 서버
→ APNs
→ iOS 앱

Android 푸시 알림

Android에서는 일반적으로 FCM(Firebase Cloud Messaging)을 사용함.

개략적인 구조는 iOS와 유사함.

알림 서버
→ FCM
→ Android 앱

다만 APNs와 FCM은 사용하는 API와 인증 방식 등 세부 구현에는 차이가 있음.

SMS

SMS는 통신사와 직접 연동하기보다 제3자 서비스를 사용하는 경우가 많음.

대표적인 서비스:

  • Twilio
  • Vonage(구 Nexmo)
알림 서버
→ SMS 제공 사업자
→ 이동통신망
→ 사용자 휴대전화

이메일

이메일 역시 제3자 이메일 서비스를 사용할 수 있음.

대표적인 서비스:

  • SendGrid
  • Mailchimp

이러한 서비스는 대량 이메일 전송뿐 아니라 전송 성공률이나 클릭률 등의 데이터 분석 기능도 제공할 수 있음.


3. 사용자 연락처 및 단말 정보 저장

알림을 보내기 위해 다음과 같은 정보가 필요함.

  • 이메일 주소
  • 전화번호
  • Device Token

이메일 주소와 전화번호 등의 기본 정보는 user 테이블에 저장하고, Device Token은 별도의 device 테이블에 저장함.

이렇게 분리하는 이유는 한 사용자가 여러 단말을 사용할 수 있기 때문임.

User A
 ├─ Device 1
 ├─ Device 2
 └─ Device 3

즉 관계는 다음과 같음.

User : Device
= 1 : N

필요한 경우 한 사용자가 등록한 모든 단말로 알림을 전송할 수 있음.


4. 개략적인 시스템 설계

알림 시스템의 주요 컴포넌트는 다음과 같음.

Service 1 ~ N

알림을 발생시키는 서비스임.

예:

  • 마이크로서비스
  • 크론잡
  • 배치 시스템
  • 분산 시스템의 다른 컴포넌트

예를 들어:

주문 서비스 → 주문 완료 알림
결제 서비스 → 결제 완료 알림
배송 서비스 → 배송 시작 알림

즉 알림 시스템은 서로 다른 서비스들이 생성하는 알림을 공통으로 처리하는 인프라 역할을 함.

알림 서버

알림 시스템의 핵심 컴포넌트임.

주요 역할:

  • 서비스들이 사용할 알림 API 제공
  • 사용자 정보 조회
  • Device Token 조회
  • 사용자 알림 설정 확인
  • 알림 템플릿 적용
  • 제3자 서비스에 전달할 Payload 생성
  • 알림 이벤트를 메시지 큐에 저장

알림 서버를 한 대만 두면 다음 문제가 발생할 수 있음.

  • SPOF
  • 처리량 한계
  • 성능 병목
  • 수평적 확장 어려움

따라서 알림 서버를 여러 대로 구성하고 DB와 캐시도 별도 컴포넌트로 분리함.

캐시

자주 조회되는 다음 정보를 저장함.

  • 사용자 정보
  • Device 정보
  • 알림 설정
  • 알림 템플릿

DB 접근을 줄이고 응답 시간을 단축할 수 있음.

데이터베이스

다음과 같은 데이터를 영구 저장함.

  • 사용자 정보
  • Device Token
  • 사용자 알림 설정
  • 알림 정보
  • 알림 로그
  • 전송 상태

메시지 큐

시스템 컴포넌트 사이의 강한 결합을 줄이는 역할을 함.

알림 서버
→ Message Queue
→ Worker

대량의 알림이 한꺼번에 발생할 경우 알림을 임시로 저장하는 버퍼 역할도 담당함.

작업 서버(Worker)

메시지 큐에서 알림 이벤트를 가져와 실제 제3자 서비스로 전달함.

Push Queue
→ Push Worker
→ APNs / FCM

SMS Queue
→ SMS Worker
→ SMS Provider

Email Queue
→ Email Worker
→ Email Provider

제3자 서비스

실제로 사용자에게 알림을 전달함.

예:

  • APNs
  • FCM
  • Twilio
  • SendGrid

제3자 서비스와 통합할 때는 새로운 서비스 사업자를 쉽게 추가하거나 기존 사업자를 제거할 수 있도록 설계하는 것이 중요함.

특정 국가나 시장에서는 특정 서비스 제공자를 사용할 수 없을 수도 있으므로 대체 사업자를 지원할 수 있어야 함.


5. 알림 API와 전송 과정

이메일 알림 API 예제

POST /api/v1/email/send

요청 예:

알림 전송 과정

  1. 서비스가 알림 API 호출
  2. 알림 서버가 캐시 또는 DB에서 사용자 정보, Device Token, 알림 설정 등의 메타데이터 조회
  3. 알림 서버가 전송할 알림 이벤트 생성
  4. 알림 종류에 맞는 메시지 큐에 이벤트 저장
  5. Worker가 메시지 큐에서 이벤트 조회
  6. Worker가 APNs, FCM, SMS, 이메일 등의 제3자 서비스로 전달
  7. 제3자 서비스가 사용자 단말로 알림 전달
서비스
→ 알림 서버
→ 메시지 큐
→ Worker
→ 외부 알림 서비스
→ 사용자

6. 안정성과 중복 처리

데이터 손실 방지

책의 설계 요구사항에서는 다음과 같이 가정함.

알림은 지연되거나 순서가 달라질 수는 있지만 시스템 내부에서 소실되어서는 안 됨.

이를 위해 알림 데이터를 지속적으로 저장하고 전송 실패 시 재시도해야 함.

한 가지 방법은 알림 로그 DB를 유지하는 것임.

알림 이벤트 생성
→ 로그 또는 지속 가능한 큐에 저장
→ 전송 시도
→ 결과 저장

전송에 실패하면 저장된 데이터를 이용해 다시 시도할 수 있음.

알림 중복 전송 방지

분산 시스템에서는 재시도로 인해 동일 이벤트가 여러 번 처리될 수 있음.

따라서 각 이벤트에 고유한 event_id를 부여할 수 있음.

event_id = 8237471

Worker가 이벤트를 받으면:

event_id 확인
       ↓
이미 처리했는가?
 ├─ YES → 폐기
 └─ NO  → 알림 전송

이를 통해 중복 발송 빈도를 줄일 수 있음.


7. 알림 시스템의 부가 기능

알림 템플릿

매번 알림 문구를 새로 작성하는 대신 미리 형식을 정의해둘 수 있음.

예:

[배송 알림]

{사용자명}님의 상품이 배송을 시작했습니다.
송장번호: {송장번호}

장점:

  • 형식의 일관성 유지
  • 오류 감소
  • 작성 시간 단축
  • 다국어 지원 용이
  • 추적 링크와 스타일 일괄 적용 가능

알림 설정

사용자가 너무 많은 알림을 받으면 알림 기능 자체를 꺼버릴 수 있음.

따라서 사용자가 종류별로 알림을 조정할 수 있어야 함.

마케팅 알림   OFF
배송 알림     ON
결제 알림     ON
이벤트 알림   OFF

알림을 보내기 전에 사용자 설정을 확인해야 함.

전송률 제한

한 사용자에게 지나치게 많은 알림을 보내지 않도록 제한함.

예:

마케팅 Push
→ 사용자당 하루 최대 3건

이를 통해:

  • 알림 피로 감소
  • 스팸 방지
  • 외부 서비스 비용 절감

등의 효과를 얻을 수 있음.

재시도 메커니즘

전송 실패 시 알림을 재시도 전용 큐로 이동시킴.

전송 실패
→ Retry Queue
→ 재시도

계속 실패할 경우 오류를 기록하고 운영자나 개발자에게 알림을 보낼 수 있음.

재시도 횟수와 재시도 간격도 제한해야 함.

푸시 알림 보안

인증되지 않은 클라이언트가 임의로 알림을 보낼 수 없어야 함.

APNs와 FCM은 각각 별도의 인증 방식을 사용함.

  • APNs

    • APNs Signing Key를 이용한 JWT Provider Token
    • 인증서 방식도 사용 가능
  • FCM

    • 서비스 계정 기반 OAuth 2.0 Access Token 사용

즉 단순한 appKey + appSecret으로 일반화하기보다 플랫폼별 인증 체계를 사용한다고 보는 것이 적절함.


8. 모니터링과 이벤트 추적

큐 모니터링

알림 시스템에서 중요한 지표 중 하나는 메시지 큐에 쌓인 알림의 수임.

Queue Size ↑

큐가 계속 증가한다면:

알림 생성 속도
>
Worker 처리 속도

일 가능성이 있음.

이 경우 다음을 확인해야 함.

  • Worker 수가 충분한가
  • 외부 서비스가 느려졌는가
  • 오류율이 증가했는가
  • 큐 처리 속도가 떨어졌는가

필요하면 Worker를 증설할 수 있음.

이벤트 추적

다음 지표를 수집하면 알림의 효과를 분석할 수 있음.

  • 전달 성공률
  • 확인율
  • 클릭률
  • 앱 실행 전환율
  • 구매 전환율

예:

Push 발송
→ 알림 확인
→ 클릭
→ 앱 실행
→ 구매

이벤트 추적 데이터는 사용자 행동과 알림 품질을 개선하는 데 활용할 수 있음.


9. 분산 시스템에서 Exactly-once가 어려운 이유

책에서는 이 부분의 참고 자료로 다음 글을 제시함.

Tyler Treat, You Cannot Have Exactly-Once Delivery

핵심 내용은 네트워크로 분리된 두 컴포넌트 사이에서 메시지가 정확히 한 번 전달됐다는 사실을 완벽하게 확인하기 어렵다는 것임.

예를 들어 서버 A가 서버 B에게 메시지를 보냈는데 ACK를 받지 못했다고 가정함.

가능한 경우:

1. 메시지가 네트워크에서 유실됨
2. B가 메시지를 받았지만 처리 전에 장애 발생
3. B가 메시지를 처리 중이지만 매우 느림
4. B가 처리를 완료함
5. B가 ACK를 보냈지만 ACK가 유실됨

A는 ACK를 받지 못했다는 사실만으로 B가 메시지를 처리했는지 알 수 없음.

블로그에서는 이러한 분산 시스템의 불확실성을 설명하기 위해 Two Generals Problem, Byzantine Generals Problem, FLP 결과 등을 함께 언급함.

FLP는 exactly-once delivery 자체에 대한 직접적인 증명이라기보다는 비동기 분산 시스템에서 장애와 합의가 갖는 근본적인 한계를 설명하는 이론적 배경으로 볼 수 있음.

At-most-once

최대 한 번 전달하는 방식.

블로그의 단순한 예에서는 메시지를 받은 뒤 처리 전에 ACK를 보냄.

메시지 수신
→ ACK
→ 처리

ACK 이후 처리 중 장애가 발생하면 Sender는 이미 성공했다고 생각하므로 재전송하지 않음.

따라서:

At-most-once
→ 중복 가능성 낮음
→ 메시지 유실 가능

알림 서비스라면 사용자가 받아야 할 알림이 사라질 수 있음.

At-least-once

최소 한 번 이상 전달하는 방식.

메시지를 처리한 뒤 ACK를 보냄.

메시지 수신
→ 처리
→ ACK

하지만 처리는 완료됐는데 ACK가 유실되면 Sender는 실패로 판단하고 다시 메시지를 보냄.

처리 완료
→ ACK 유실
→ 재전송
→ 동일 메시지 다시 처리

따라서:

At-least-once
→ 메시지 유실 가능성을 줄임
→ 중복 처리 가능

알림 서비스라면 동일한 알림이 두 번 전달될 수 있음.

Exactly-once와 실무적인 해결 방법

이상적인 목표는:

메시지 유실 없음
+
중복 없음
=
Exactly-once

이지만 네트워크에서 메시지나 ACK가 유실될 수 있으므로 네트워크 수준에서 exactly-once delivery를 완벽하게 보장하기 어려움.

따라서 실무에서는 중복 가능성을 받아들이고 애플리케이션 계층에서 이를 흡수함.

대표적인 방법은 두 가지임.

멱등성(Idempotency)

같은 연산을 여러 번 수행해도 최종 결과가 같도록 설계함.

상태 = 활성화

를 여러 번 수행해도 최종 상태는 동일함.

중복 제거(Deduplication)

각 메시지에 고유한 Event ID를 부여하고 처리 이력을 확인함.

event_id = abc123

처음 들어온 경우:

처리 이력 없음
→ 처리
→ 완료 기록

같은 이벤트가 다시 들어온 경우:

이미 처리됨
→ 폐기

알림 발송은 같은 함수를 두 번 실행하면 실제 알림도 두 번 나갈 수 있으므로 자연스럽게 멱등한 연산이 아님.

따라서 알림 시스템에서는 Event ID 기반 중복 제거가 특히 중요함.

전체 흐름은 다음과 같음.

At-least-once
       ↓
중복 가능
       ↓
Event ID
       ↓
Deduplication 또는 Idempotency
       ↓
중복으로 인한 부작용 방지

즉 분산 알림 시스템에서는 중복 전달 자체를 완전히 없애려 하기보다, 재전송을 허용하고 Event ID와 중복 제거 또는 멱등 처리를 이용해 중복으로 인한 문제를 흡수하는 방식이 현실적임.


10. 최종 설계 정리

최종적인 알림 시스템 구조는 다음과 같음.

추가적으로 다음 기능을 포함함.

  • Notification Log
  • Retry Queue
  • Rate Limiter
  • 알림 Template
  • User Preference
  • Deduplication
  • Monitoring
  • Event Tracking

핵심은 단순히 알림을 보내는 것에 그치지 않고 다음 사항을 함께 고려하는 것임.

  • 알림의 유실 방지
  • 중복 발송 억제
  • 대량 요청 처리
  • 외부 서비스 장애 대응
  • 사용자별 알림 설정
  • 전송률 제한
  • 시스템 모니터링
  • 알림 효과 분석
profile
Live a life you will remember

0개의 댓글