NX開発推進部プロダクト開発第2グループの齋藤です。
最近はARC Raidersというゲームにハマっています。
今回は最近作成しているPush通知基盤のアーキテクチャを紹介します。
背景
今まで、SaaSのPush通知サービスを使用していましたが、運用面で次の課題がありました。
- 対象を絞って送信したいときにわざわざSQLを書く必要がある(使い勝手の問題)
- 送信数の増加に伴うコストの高騰
そこでAWSでPush通知基盤を構築することになりました。
新基盤では、送信数の増減に応じて自動的にスケールする仕組みを重視し、
SQSとLambdaを組み合わせたイベント駆動型のアーキテクチャを採用しています。
また、Push通知の送信対象はAndroid、iOSアプリになります。WebのPush通知は対象外です。
設計の経緯
今回のアーキテクチャ設計では、正直なところかなり苦労しました。
私自身、これまで既存システムの機能追加や改修が中心で、
ゼロから基盤のアーキテクチャを設計する経験が少なかったためです。
最初は「とりあえずAPIからSNSに直接送信すればいいのでは?」と考えていましたが、
次のような課題に直面しました。
- 大量送信時にAPIのレスポンスが遅延する問題
- 送信エラー時のリトライ処理をどう実装すべきか
- 将来的なユーザー増加にどう対応するか
そこで、類似事例を調べたり、社内の有識者にレビューをお願いしたりする中で、
「イベント駆動型アーキテクチャ」と「処理の段階的な分離」という考え方に辿り着きました。
SQSとLambdaを組み合わせることで、スケーラブルで柔軟な処理が実現できることを学び、
現在のイベント駆動型の構成(API → SQS → Lambda → SNS)に落ち着きました。
(参考: AWS – イベント駆動型アーキテクチャ (EDA) とは)
構成
今回の構成はこちらになります。

アプリケーションへのPush通知配信は、Amazon SNS経由でFCM(Firebase Cloud Messaging)を利用して行っています。
これにより、AndroidとiOSの両プラットフォームに対して統一的にPush通知を送信できます。
Push通知の送信フロー
即時送信
例えば「いいね」通知のような、リアルタイムでのPush送信の手順です。
- アプリまたは管理画面からECS上のBackend APIを呼び出す
- APIは送信リクエストをAmazon SQS(Input Queue)にキューイングする
- Dispatch Lambdaが起動し、次の処理を実行する
- 送信対象ユーザーの選定
- 大量送信時のチャンク分割(送信数が多い場合は複数のチャンクに分割)
- Notification Queueへの振り分け
- Publish LambdaがNotification Queueからメッセージを取得し、Amazon SNSを通じてFCMにPush通知を配信する
API、Input Queue、Notification Queueとキューイングを段階的に分けることで、次の特性を実現しています。
- Dispatch Lambdaでの処理時間が長くなっても、APIレスポンスには影響しない
- 送信対象の選定処理と実際の配信処理を分離し、それぞれ独立してスケール可能
スケジュール送信
「毎日朝9時に通知を送りたい」といった時刻指定の送信要件に対応するため、EventBridge Schedulerを活用しています。
- Backend APIからEventBridge Schedulerに送信スケジュールを登録
- 指定時刻になるとSchedulerがLambdaを起動
- 以降は即時送信と同様のフローで処理
スケーラビリティのポイント
本アーキテクチャでは、将来的なユーザー増加を見据えて、次のスケーラビリティを重視しています。
自動スケールする仕組み
- SQSは、メッセージが溜まっても自動的にキューイングされ、処理の平準化が可能
- Lambdaは、同時実行数が自動的にスケールし、送信数の増減に柔軟に対応
- SNSは、AWSのマネージドサービスとして、大量配信にも耐えられる
このため、例えば今は1日数万通の配信でも、将来的に数十万通、数百万通に増加しても、 アーキテクチャを大きく変更することなく対応できる設計になっています。
処理の分離によるボトルネック回避
3つの処理層に分離したことで、各処理が独立してスケールできます。
- APIレイヤーは、ユーザーからのリクエスト受付に専念
- Dispatch Lambdaは、送信対象の選定とチャンク分割を担当
- Publish Lambdaは、実際のPush配信を担当
仮にDispatch Lambdaで重い処理が発生しても、APIのレスポンスには影響しません。
また、各Lambdaは独立してスケールするため、処理のボトルネックが発生しにくい構造です。
ログ・分析基盤
Push通知の送信ステータスや開封率などの分析データは、次の流れで収集・蓄積しています。
- SNSからKinesis Data Firehoseへ送信結果を連携
- FirehoseがS3にデータを保存
- AWS Glueでデータをカタログ化
- Amazon AthenaでSQL形式の分析クエリを実行
分析基盤にGlue + Athenaを採用した背景は次の通りです。
- リアルタイム分析が不要で、日次・週次での集計分析が中心のため、バッチ処理で十分
- サービス規模から想定される送信数では、ビッグデータ処理基盤は過剰
- クエリ実行時のみ課金されるAthenaは、分析頻度が高くない用途に適している
- Athenaは、RedshiftやOpenSearchのようなクラスタ管理が不要で、運用負荷が低い
デバイストークン管理
各デバイスのトークン情報はAmazon RDSで管理しています。
連続して送信失敗が発生したトークンには無効フラグを立て、以降の送信対象から除外します。
これにより、無駄な送信を防ぎ、コスト最適化と送信効率の向上を図っています。
今後の展望
図中に記載の管理画面については現在開発中です。
管理画面では、次の機能を提供予定です。
- Push通知の配信履歴の確認
- 配信スケジュールの設定・管理
- 配信対象の絞り込み設定
- 開封率などの統計情報の可視化
まとめ
今回、SaaSからAWSへPush通知基盤を移行し、スケーラブルな構成を構築しました。
アーキテクチャ設計の経験が少ない中での挑戦でしたが、
調査や有識者からのレビューを通じて、イベント駆動型の設計思想を学ぶことができました。
特に学んだのは「処理を適切に分離することの重要性」です。
単純にAPIから直接SNSに送信する構成も可能でしたが、
SQSとLambdaを挟むことで、スケーラビリティ、可用性、保守性が大きく向上しました。
現在は安定稼働しており、今後のユーザー増加にも対応できる基盤が整ったと考えています。
引き続き、管理画面の開発や機能拡張を進めていきます。
齋藤拓海