システム設計:スケーラブルな通知サービスの設計(Email/Push/SMS)
問題¶
Every app sends notifications (Emails, Push, SMS). Design a scalable notification system.
解答・設計¶
要件定義¶
機能要件:
- 数百万件の通知を送信できる
- Email / Push / SMS の複数チャネルに対応
- 失敗時にリトライできる
非機能要件:
- 高スループット(ピーク時に数万件/秒)
- 高可用性(通知の欠損は許されない)
- チャネルごとに独立してスケールできる
アーキテクチャ設計¶
フロー:
Event → Notification Service → Queue → Workers → Channels
[イベントソース]
- ユーザーアクション(注文完了・フォローなど)
- スケジュールバッチ(朝のメール配信など)
- 内部サービスからの呼び出し
↓
[Notification Service]
- ユーザー設定取得(どのチャネルで通知するか)
- テンプレート解決(通知文面の生成)
- チャネルごとにキューへ振り分け
↓
[Message Queue] (Kafka / SQS / RabbitMQ)
- email-queue
- push-queue
- sms-queue
→ チャネルごとに分離してスケール可能
↓
[Workers] (チャネルごとに独立)
- Email Worker → SendGrid / AWS SES
- Push Worker → FCM (Android) / APNs (iOS)
- SMS Worker → Twilio / AWS SNS
↓
[外部プロバイダー]
重要な設計ポイント¶
1. キューで非同期化する
→ 通知の送信は即時でなくてよい
→ 外部プロバイダーへの依存をデカップリング
→ プロバイダーがダウンしても通知は失われない
2. リトライ戦略
→ Exponential Backoff: 1s → 2s → 4s → 8s...
→ 最大リトライ回数を設定(例: 5回)
→ Dead Letter Queue(DLQ)で失敗分を保管・分析
3. 冪等性(Idempotency)
→ 同じ通知を2回送らない
→ notification_id を使って重複チェック(Redis で管理)
4. レートリミット
→ 外部プロバイダーのレート制限に従う
→ ユーザーへの過剰通知を防ぐ(1日N件まで)
5. ユーザー設定の優先
→ 通知オフ設定・Do Not Disturb 時間帯を尊重
→ Preference Service を分離して管理
データモデル¶
-- 通知ログ
CREATE TABLE notifications (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
channel ENUM('email', 'push', 'sms'),
template_id VARCHAR(100),
status ENUM('pending', 'sent', 'failed'),
retry_count INT DEFAULT 0,
created_at TIMESTAMP,
sent_at TIMESTAMP
);
-- ユーザー通知設定
CREATE TABLE notification_preferences (
user_id UUID PRIMARY KEY,
email_enabled BOOLEAN DEFAULT TRUE,
push_enabled BOOLEAN DEFAULT TRUE,
sms_enabled BOOLEAN DEFAULT FALSE,
quiet_hours_start TIME,
quiet_hours_end TIME
);
スケール見積もり¶
前提: DAU 1000万、1ユーザーあたり平均5通知/日
→ 5000万通知/日 ≈ 578通知/秒(平均)
→ ピーク時は10倍 ≈ 5780通知/秒
キューの分散:
- Email: 300/秒 → Worker 3台
- Push: 250/秒 → Worker 2台
- SMS: 28/秒 → Worker 1台
面接でのポイント¶
- 「キューで非同期化」「チャネルごとにワーカーを分離」の2点は必須
- リトライ・冪等性・DLQ まで言及すると信頼性の理解を示せる
- ユーザー設定(Do Not Disturb)への言及で UX 観点も評価される
- 数値見積もりを出せると定量的な設計力として加点