Orivel Orivel
メニューを開く

スケーラブルな通知サービスの設計

このシステム設計ベンチマークに対する各AIの回答と比較結果を確認できます。

いいね・お気に入り機能を使うにはログインまたは新規登録が必要です。 新規登録

X f L

目次

お題概要

比較ジャンル

システム設計

お題作成モデル

回答モデル

採点モデル

お題本文

あなたは急成長中のソーシャルメディア企業のシニアソフトウェアエンジニアです。あなたのタスクは、スケーラブルで信頼性の高い通知サービスを設計することです。このサービスは、新しいフォロワー、投稿への「いいね」、コメント、ダイレクトメッセージなど、さまざまなイベントに関してユーザーに通知を送信する役割を担います。

補足情報

システムは以下の要件を満たす必要があります: 1. **通知タイプ:** プッシュ通知(モバイルデバイス向け)、アプリ内通知(アプリ内で表示されるもの)、およびメール通知。 2. **スケール:** プラットフォームは1億のデイリーアクティブユーザーを持ちます。システムはピーク時に毎秒50,000件の通知リクエストを処理できる必要があります。 3. **レイテンシ:** プッシュ通知とアプリ内通知の99%は、イベント発生から2秒以内にユーザーのデバイスへ配信されるべきです。 4. **信頼性:** システムはすべての通知に対して少なくとも一度の配信を保証しなければなりません。コンポーネントが故障した場合でも通知が失われてはなりません。 5. **パーソナライズ:** ユーザーは通知設定を構成できるべきです(例:いいねに対するメール通知を無効にする)。 高レベルなシステムアーキテクチャを提案してください。主要コンポーネント、それらの責務、および相互作用を説明してください。技術選択(例:データベース、メッセージキュー、キャッシュ)についての理由を説明し、トレードオフを議論してください。設計がスケーラビリティ、低レイテンシ、および信頼性の要件をどのように満たすかについても説明してください。

採点方針

高品質な回答は一貫性があり理路整然としたシステム設計を提示します。評価は以下の側面に焦点を当てます: - **アーキテクチャの明確さ:** 提案されたアーキテクチャは論理的かつ明確に説明されるべきであり、主要コンポーネント(例:APIゲートウェイ、通知サービス、ワーカー、メッセージキュー)とそれらの間のデータフローを詳述すること。 - **スケーラビリティとパフォーマンス:** 設計は、指定された高負荷および低レイテンシ要件をどのように処理するかを効果的に説明する必要があります。これには水平スケーリング、ロードバランシング、適切なデータストアやキャッシュ機構の使用といった戦略の議論が含まれます。 - **信頼性とフォールトトレランス:** 回答は回復力のあるシステムを構築する理解を示すべきです。設計がどのようにして at-least-once 配信を保証し、リトライ、冗長化、デッドレターキューなどを通じて個々のコンポーネントの障害に対処するかを説明してください。 - **技術選択とトレードオフ:** 特定の技術(例:Kafka vs. RabbitMQ、NoSQL vs. SQLデータベース)を選択する正当性は妥当であるべきです。選択したアプローチのトレードオフを明確に述べ、唯一の「完璧な」解決策は存在しないという理解を示してください。

回答

スケーラブルな通知サービスは、イベントの取り込み、プリファレンス評価、通知の永続化、チャネル固有の配信、および配信追跡を分離する、非同期イベント駆動型プラットフォームとして構築する必要があります。最も重要な設計原則は、フォロー、いいね、コメント、ダイレクトメッセージなどのソースプロダクトシステムが、プッシュ通知プロバイダー、メールプロバイダー、またはユーザーデバイスを同期的に呼び出してはならないということです。それらは、メッセージングレイヤーに耐久性のあるイベントを発行し、通知プラットフォームは、強力なリトライおよびべき等性保証をもって、それらのイベントを独立して処理する必要があります。

アーキテクチャは、大まか...

全文を表示

スケーラブルな通知サービスは、イベントの取り込み、プリファレンス評価、通知の永続化、チャネル固有の配信、および配信追跡を分離する、非同期イベント駆動型プラットフォームとして構築する必要があります。最も重要な設計原則は、フォロー、いいね、コメント、ダイレクトメッセージなどのソースプロダクトシステムが、プッシュ通知プロバイダー、メールプロバイダー、またはユーザーデバイスを同期的に呼び出してはならないということです。それらは、メッセージングレイヤーに耐久性のあるイベントを発行し、通知プラットフォームは、強力なリトライおよびべき等性保証をもって、それらのイベントを独立して処理する必要があります。

アーキテクチャは、大まかに言うと、イベントプロデューサー、取り込みAPI、耐久性のあるイベントログ、通知プロセッサー、ユーザープリファレンスサービス、テンプレートおよびパーソナライゼーションサービス、通知ストア、チャネルファンアウトキュー、チャネル固有の配信ワーカー、サードパーティプロバイダー統合、インアプリ配信用のリアルタイムゲートウェイ、およびオブザーバビリティ/リトライインフラストラクチャといったコンポーネントを含みます。

プロダクトサービスは、ユーザー向けの操作が発生したときに通知イベントを生成します。たとえば、ソーシャルグラフサービスは新しいフォロワーイベントを発行し、投稿サービスはいねまたはコメントイベントを発行し、メッセージングサービスはダイレクトメッセージイベントを発行します。各イベントには、イベントID、イベントタイプ、アクターユーザーID、受信者ユーザーIDまたは受信者セット、オブジェクトID、作成タイムスタンプ、およびレンダリングに必要なメタデータが含まれます。プロデューサーはこれらのイベントを通知取り込みAPIに、または直接耐久性のあるメッセージバスに送信します。取り込みAPIはスキーマを検証し、プロデューサーを認証し、べき等性キーを割り当てるか検証し、プロデューサーに応答する前にイベントを耐久性のあるログに書き込みます。これにより、ダウンストリームプロセッサーが失敗した場合でも通知の損失を防ぎます。

耐久性のあるメッセージングバックボーンには、Apache Kafka、Amazon MSK、Google Pub/Sub、またはPulsarを使用します。Kafka/Pulsarは、高スループット、パーティション順序、保持、リプレイ、コンシューマーグループ、および耐久性のあるストレージを提供するため、適しています。毎秒50,000件の通知リクエストの場合、イベントストリームは、必要に応じてユーザーレベルの順序付けのために受信者ユーザーIDで、または厳密なユーザーごとの順序付けがあまり重要でない場合はイベントIDでパーティション化する必要があります。受信者によるパーティション化は、単一ユーザーのアプリ内通知の順序誤りを回避するのに役立ちますが、有名人アカウントやグループイベントのホットパーティションを作成する可能性があります。数百万人のフォロワーに通知を生成するような大規模なファンアウトの場合、別のファンアウトサービスが受信者をバッチに分割し、多数のパーティションにわたって派生した受信者ごとの通知ジョブを発行する必要があります。

通知プロセッサーは、耐久性のあるイベントログから生のイベントを消費します。それらの責任は、受信者を決定し、ユーザープリファレンスを取得し、レート制限とサイレントアワーを適用し、イベントを重複排除し、チャネル固有の通知レコードを生成し、配信ジョブを発行することです。ユーザーの投稿へのコメントのような直接イベントの場合、受信者セットは小さくなります。有名人が投稿するようなファンアウトイベントの場合、プロセッサーはすべてのファンアウトを同期的に行うことを避けるべきです。ファンアウトジョブを作成し、ソーシャルグラフストアからのバッチ読み取りを使用して、受信者をシャードで処理する必要があります。これにより、1つの非常に大きなイベントが通常の通知の低レイテンシパスをブロックするのを防ぎます。

ユーザープリファレンスサービスは、ユーザーがいいね、コメント、フォロワー、ダイレクトメッセージに対してプッシュ、アプリ内、またはメール通知を希望するかどうかなどの設定を保存します。プリファレンスは、DynamoDB、Cassandra、ScyllaDB、またはシャーディングされたリレーショナルデータベースなどの高可用性データベースに保存する必要があります。アクセスパターンは主にユーザーIDと通知タイプによるキーバリュー検索であるため、分散キーバリューまたはワイドカラムストアが適切です。2秒のレイテンシターゲットを満たすために、プリファレンスはRedis、Memcached、または短いTTLを持つローカルインプロセスキャッシュにもキャッシュする必要があります。プリファレンス更新はソースオブトゥルースデータベースに書き込まれ、無効化イベントを通じてキャッシュに伝播されます。トレードオフは、キャッシュの鮮度により、最近変更されたプリファレンスが適用されるまでに数秒かかる可能性があることです。プリファレンスの厳密な一貫性が必要な場合は、プロセッサーはキャッシュミス時または最近更新されたユーザーに対してデータベースへの読み取りを行うことができます。

テンプレートおよびパーソナライゼーションサービスは、通知コンテンツをレンダリングします。「Alex liked your post」や「Maya commented: ...」のようなテンプレートにイベントタイプをマッピングします。ローカライゼーション、ディープリンク、画像URL、およびチャネル固有のペイロード制約を処理します。テンプレート定義は設定データベースに保存でき、変更が頻繁ではないため積極的にキャッシュできます。レンダリングは配信ジョブが発行される前に行われるべきであり、これにより各ジョブは自己完結型になり、安全にリトライできるようになります。

通知ストアは、ユーザーが見ることができるアプリ内通知および配信状態のソースオブトゥルースです。適切な選択肢は、Cassandra、DynamoDB、ScyllaDB、または受信者ユーザーIDでパーティション化され、通知タイムスタンプでソートされたその他の水平スケーラブルストアです。主なアクセスパターンは「ユーザーXの最新の通知を取得する」であるため、テーブルは受信者_user_idをパーティションキーとして、created_atまたはnotification_idをソートキーとして使用できます。サービスは、アプリ内配信ジョブの発行と同時、またはその前にアプリ内通知レコードを書き込みます。レコードには、通知ID、受信者、タイプ、コンテンツ、ステータス、既読/未読状態、タイムスタンプ、および重複排除キーが含まれます。このストアは、WebSocket配信が失敗した場合でも、ユーザーがアプリを開いたときに通知を確認できることを保証します。

プリファレンスとテンプレートが適用された後、プロセッサーは個別のチャネルキューにジョブを発行します:プッシュキュー、アプリ内キュー、およびメールキュー。各チャネルには異なるレイテンシと信頼性の特性があるため、キューを分離することは重要です。プッシュおよびアプリ内キューはレイテンシに敏感であり、最小限のバックログで高スループットのためにプロビジョニングする必要があります。メールはレイテンシに敏感ではなく、より長い遅延、プロバイダーのスロットリング、およびバッチ処理を許容できます。個別のキューは、遅いメールプロバイダーがプッシュ配信に影響を与えるのを防ぎます。

プッシュ配信ワーカーはプッシュキューから消費し、Apple Push Notification service、Firebase Cloud Messaging、またはその他のモバイルプッシュプロバイダーに通知を送信します。デバイスートークンは、トークン、プラットフォーム、アプリバージョン、ロケール、および最終アクセス時刻スタンプでキー付けされたユーザーIDのデバイスレジストリに保存されます。レジストリは分散キーバリューストアを使用し、アクティブなトークンをキャッシュできます。プッシュワーカーは、プロバイダーの応答を処理し、無効なトークンを削除し、指数バックオフで一時的な障害をリトライし、配信試行を記録する必要があります。プッシュプロバイダーの確認は、ユーザーが通知を見たことを保証するのではなく、プロバイダーがそれを受け入れたことを示すだけなので、システムはプロバイダーの受け入れと実際のユーザーの受信を区別する必要があります。

アプリ内配信には2つのパスがあります。まず、通知は通知ストアに永続化されます。次に、アプリ内配信ワーカーがリアルタイムゲートウェイを介して、現在接続されているユーザーのデバイスに送信します。ゲートウェイは、WebSocket、HTTP/2ストリーム、またはモバイルプッシュのような永続接続インフラストラクチャを使用して実装できます。ゲートウェイノードは、メモリ内でユーザー接続状態を維持し、プレゼンス情報を分散プレゼンスサービスに発行します。ルーティングレイヤーまたはRedis/NATSベースのプレゼンスマップは、どのゲートウェイノードが現在ユーザーの接続を所有しているかをアプリ内ワーカーに伝えます。ユーザーがオフラインであるか、ゲートウェイの送信が失敗した場合でも、永続化された通知は次のセッションでアプリの通知受信トレイAPIを介して取得されるため、通知は失われません。低レイテンシのために、ゲートウェイノードはユーザーの近くに地域的に展開されるべきであり、アプリ内キューは可能な限り同じ地域でワーカーによって処理されるべきです。

メール配信ワーカーはメールキューから消費し、SES、SendGrid、またはMailgunなどのプロバイダーを介して送信します。プロバイダーのフェイルオーバー、バウンス処理、抑制リスト、購読解除コンプライアンス、およびプロバイダーごとのレート制限をサポートする必要があります。メール通知は、いいねのような低優先度のイベントタイプに対してバッチ処理またはダイジェスト処理できますが、ダイレクトメッセージやセキュリティ関連のイベントは即座に送信される場合があります。メールは遅く、より高価であるため、ユーザープリファレンスとレート制限は特に重要です。

信頼性は、耐久性のある書き込み、少なくとも1回の処理、べき等性、リトライ、およびデッドレターキューによって達成されます。取り込みレイヤーは、イベントがKafka/Pulsarに耐久性を持って書き込まれた後にのみプロデューサーに応答します。コンシューマーは、通知レコードの書き込みと下流のチャネルジョブの発行に成功した後のみオフセットをコミットします。リトライは重複を作成する可能性があるため、すべてのイベントと通知には安定したべき等性キーが必要です。たとえば、いいね通知のキーはrecipient_id + actor_id + post_id + event_typeになる可能性があり、コメント通知のキーにはcomment_idが含まれる場合があります。通知ストアはこのキーの一意性を強制するか、プロセッサーが条件付き書き込みを実行します。配信ワーカーも試行IDとべき等な状態遷移を使用する必要があり、重複ジョブが重複するアプリ内レコードや重複メールを作成しないようにします。システムは少なくとも1回の配信を保証しますが、正確に1回の配信は保証しないため、クライアントも通知IDで重複を排除する必要があります。

デッドレターキューは、ポイズンメッセージ、不正な形式のイベント、繰り返しのプロバイダー障害、またはレンダリングできないレコードに必要です。リプレイツールを使用すると、オペレーターは問題を修正し、元の耐久性のあるログまたはデッドレターキューからイベントを再処理できます。Kafkaの保持期間は、運用回復をサポートするのに十分な長さである必要があります。たとえば数日間です。重要なメタデータと配信状態も、監査のために通知データベースに永続化する必要があります。

1日あたり1億人のアクティブユーザーと毎秒50,000件の通知リクエストという規模の要件を満たすために、すべての主要サービスは水平スケーラブルで、可能な限りステートレスである必要があります。取り込みAPIはロードバランサーの後ろでスケールします。Kafka/Pulsarトピックは、ピークスループットとコンシューマーの並列処理をサポートするのに十分な幅でパーティション化されます。プロセッサーと配信ワーカーは、オートスケーリンググループまたはKubernetesデプロイメントで実行され、キューラグ、CPU、プロバイダーレイテンシ、およびリクエストレートに基づいてスケールします。データベースはユーザーIDでパーティション化され、負荷を分散します。ホットキーの問題は、シャーディングされたファンアウトジョブ、有名人ユーザーの特別な処理、およびバックプレッシャーで処理する必要があります。非常に大規模なファンアウトの場合、システムは低優先度の通知でプルベースのファンアウトを使用する場合があります。フォロワーごとに1つの通知をすぐに書き込むのではなく、イベントを1回保存し、ユーザーがアプリを開いたときにそれをマテリアライズします。これにより書き込み増幅が削減されますが、読み取りの複雑さが増し、ダイレクトメッセージやコメントには適さない場合があります。

プッシュおよびアプリ内通知の99%に対する2秒のレイテンシターゲットは、クリティカルパスを短く保つことによって達成されます:プロデューサーから耐久性のあるログへ、キャッシュからのプロセッサープリファレンスルックアップ、通知レコード書き込み、チャネルキューへの発行、およびウォームワーカーによる即時配信。プッシュおよびアプリ内ワーカーはピーク負荷のために過剰にプロビジョニングされるべきであり、キューはダイレクトメッセージやコメントが低優先度のいいねよりも優先されるように優先レーンを使用する必要があります。地域展開はネットワークレイテンシを削減します。複数の地域にいるユーザーの場合、ルーティングは受信者のホーム地域に基づいて行うことができ、災害復旧のためにクロスリージョンレプリケーションを行います。設計は、内部処理時間だけでなく、イベント作成からプロバイダーの受け入れまたはゲートウェイ送信までのエンドツーエンドレイテンシを測定する必要があります。

オブザーバビリティは不可欠です。プラットフォームは、リクエストレート、パーティションごとのキューラグ、処理レイテンシ、プリファレンスキャッシュヒット率、通知作成失敗率、プロバイダーエラー率、リトライ回数、デッドレターボリューム、WebSocket配信成功率、プッシュプロバイダー受け入れレイテンシ、およびエンドツーエンドのp50/p95/p99レイテンシを追跡する必要があります。分散トレーシングは、元のイベントIDをすべてのコンポーネントに引き継ぐ必要があります。アラートは、キューラグの増加、失敗率の上昇、プロバイダーのスロットリング、データベース書き込みレイテンシ、およびレイテンシSLOの未達時に発生する必要があります。

いくつかのトレードオフがあります。KafkaまたはPulsarは運用上の複雑さを増しますが、この規模での少なくとも1回の配信に必要な耐久性、リプレイ、およびスループットを提供します。CassandraまたはDynamoDBは高い書き込みスケーラビリティと可用性を提供しますが、アドホッククエリの機能は限られているため、分析は別のデータウェアハウスに送信する必要があります。プリファレンスのキャッシュはレイテンシを改善しますが、短期間の一貫性の問題が発生します。少なくとも1回の配信は、正確に1回の配信よりもはるかにシンプルで信頼性が高いですが、システムはべき等性キーとクライアントサイドの重複排除を使用して重複を許容する必要があります。書き込み時のファンアウトは受信トレイの読み取りを高速化しますが、高フォロワーイベントではコストがかかる可能性があります。読み取り時のファンアウトは書き込みを節約しますが、ランキングと読み取り時のマテリアライゼーションを複雑にします。ハイブリッドモデルが通常最善です:ダイレクト、重要、および通常のボリュームの通知には書き込み時のファンアウト、大規模な低優先度のイベントには読み取り時のファンアウトまたはバッチファンアウトを使用します。

要約すると、サービスは、パーティション化されたメッセージストリーム、ステートレスプロセッサー、キャッシュされたプリファレンスルックアップ、永続化された通知ストレージ、個別のチャネルキュー、チャネル固有のワーカー、および強力なリトライ/べき等性メカニズムを備えた、耐久性のあるイベント駆動型アーキテクチャを使用する必要があります。この設計は、毎秒50,000件の通知リクエストに水平スケーリングし、キャッシュと低レイテンシキューを通じてプッシュおよびアプリ内配信を2秒のp99ターゲット内に維持し、イベントと通知レコードを永続化してから進捗を承認することで通知が失われないことを保証します。

判定

1位 | 勝者

勝利票

3 / 3

平均スコア

89
採点モデル OpenAI GPT-5.4

総合点

92

総評

回答Aは、明確なコンポーネントの責任、現実的なデータフロー、運用上の懸念への強い配慮を備えた、包括的で一貫性のあるハイレベルアーキテクチャを提示しています。すべての必須チャネル、レイテンシ目標、少なくとも1回の配信セマンティクス、プリファレンス処理、大規模なファンアウトシナリオ、べき等性、リトライ、永続化、オブザーバビリティに直接対応しています。技術的な議論はバランスが取れており、ニュアンスに富んでおり、ファンアウトオンライト対ファンアウトオンリード、キャッシュの一貫性、Kafka/Pulsarの運用上の複雑さといった具体的なトレードオフが含まれています。主な弱点は、やや長すぎてもう少し簡潔にできる可能性があることですが、技術的には強力で、プロンプトに強く適合しています。

採点詳細を表示

設計の質

重み 30%
92

このアーキテクチャは、取り込み、耐久性のあるログ、プロセッサ、プリファレンスサービス、テンプレートサービス、通知ストア、チャネルごとのキュー、配信ワーカー、リアルタイムゲートウェイ、オブザーバビリティがすべて一貫して組み合わされており、エンドツーエンドでよく構造化されています。また、永続化されたアプリ内状態とリアルタイム配信を区別し、ファンアウトを最優先事項として扱っています。

完全性

重み 20%
94

すべての必須通知タイプ、ユーザープリファレンス、スケール、レイテンシ、信頼性、テクノロジーの選択、トレードオフをカバーしています。また、デバイスレジストリ、デッドレターキュー、べき等性キー、ファンアウトバッチ処理、リージョンデプロイメント、オブザーバビリティ、リカバリツールなど、重要な欠落していた実用的な懸念事項も追加しています。

トレードオフの説明力

重み 20%
91

Kafka/Pulsar、NoSQLの選択肢、キャッシュの一貫性、少なくとも1回対正確に1回、ファンアウトオンライト対ファンアウトオンリードについて、強力な比較推論を提供しています。これらのトレードオフは具体的であり、ワークロードと製品の動作に直接結びついています。

拡張性・信頼性

重み 20%
93

これは大きな強みです。この設計は、水平スケーリング、パーティショニング、チャネルごとのキューの分離、ホットキー緩和、リトライ、コンシューマーオフセット処理、重複排除のための条件付き書き込み、デッドレターキュー、リプレイ、確認前の耐久性を明確に説明しています。少なくとも1回の配信と2秒のターゲットを、現実的なメカニズムで直接サポートしています。

分かりやすさ

重み 10%
84

説明は、長文であるにもかかわらず、明確で論理的に順序付けられており、正確です。データフローをうまく伝えていますが、長さのために、より構造化された回答よりも少し密度が高く、すぐにスキャンしにくくなっています。

総合点

92

総評

回答Aは、非常に詳細かつ堅牢なシステム設計を提供しています。セレブリティアカウントのファンアウト、特定の冪等性キーの構築、少なくとも1回の配信のニュアンスなど、複雑な分散システム特有の課題に対する深い理解を示しています。アーキテクチャは非常に精緻で、論理的根拠が明確であり、洗練されたソリューションとトレードオフの議論をもって全ての要件に明示的に対応しており、シニアソフトウェアエンジニアに期待される専門知識を反映しています。

採点詳細を表示

設計の質

重み 30%
95

回答Aは、非常に詳細かつ論理的なアーキテクチャを提示しており、関心を明確に分離し、大規模ファンアウトや2パスアプリ内配信のような複雑なシナリオに対して堅牢なソリューションを提供しています。コンポーネント間の相互作用も明確に定義されています。

完全性

重み 20%
92

回答Aは、特定の冪等性キーの例、詳細なオブザーバビリティ、オンライト対オンリードのファンアウト戦略のニュアンスなど、高度なトピックを含む全ての要件を包括的に扱っており、非常に完全な理解を示しています。

トレードオフの説明力

重み 20%
90

回答Aは、設計全体を通してトレードオフの議論を統合し、基本的なシステム設計のトレードオフ(例:少なくとも1回対ちょうど1回、ファンアウト戦略)を明示的に強調しており、技術選択を超えた影響に対する深い理解を示しています。

拡張性・信頼性

重み 20%
93

回答Aは、スケーラビリティと信頼性の両方について優れたカバレッジを提供しており、パーティショニング戦略、コンシューマーオフセットコミット、確認応答前の永続的な書き込み、ホットキー処理、優先度付きキューなどの具体的なメカニズムを詳述し、実装の詳細に対する強い理解を示しています。

分かりやすさ

重み 10%
88

回答Aは非常に明瞭で、構成が良く、専門的な言葉遣いがされているため、その深さにもかかわらず複雑な設計を容易に追うことができます。論理的な流れは優れています。

総合点

84

総評

回答Aは、セレブリティのファンアウト、書き込み時ファンアウトと読み込み時ファンアウトのハイブリッド、冪等性キーの構築、WebSocketのプレゼンスルーティング、リージョン展開、キューの優先レーン、プロバイダーの受け入れとユーザーの受信の区別といった、微妙で重要な問題に取り組んだ、深く考察されたプロセンドリブンなシステム設計を提供します。トレードオフは表面的なリストアップではなく、文脈の中で議論されています。物語は長いですが首尾一貫しており、シニアレベルの深さを示しています。軽微な弱点:視覚的な図や、スキャンを容易にする構造化された見出し/表が不足しています。

採点詳細を表示

設計の質

重み 30%
85

包括的なコンポーネントの内訳。ファンアウト、受信者ごとのパーティショニング、プレゼンスルーティング、個別のチャネルキュー、および信頼できるソースとしての永続的な通知ストアの洗練された処理。セレブリティのファンアウトや優先レーンなどの微妙な問題も扱っています。

完全性

重み 20%
85

取り込み、永続ログ、プロセッサ、設定、テンプレート、通知ストア、チャネルキュー、ワーカー、WebSocketゲートウェイ、デバイスレジストリ、DLQ、オブザーバビリティ、リージョン展開を網羅し、4つの要件すべてを明示的に処理しています。

トレードオフの説明力

重み 20%
85

文脈の中で具体的なトレードオフを議論しています:at-least-once対exactly-once、書き込み時ファンアウト対読み込み時ファンアウトのハイブリッド、キャッシュの鮮度低下対一貫性、受信者ごとのパーティショニング対イベントID、Kafkaの運用上の複雑さ対耐久性のメリット。

拡張性・信頼性

重み 20%
85

強力な信頼性のストーリー:ACK前の永続書き込み、下流の成功後のオフセットコミット、具体的な例を含む冪等性キー、再生ツールを備えたDLQ、ホットキー緩和、レイテンシのためのリージョン展開、優先レーン。

分かりやすさ

重み 10%
70

構造化された文章ですが、非常に長く、視覚的な補助が少ないです。論理的な流れにもかかわらず、密な段落はスキャンを困難にしています。

スケーラブルな通知サービスアーキテクチャ

システム概要

通知サービスは、分散型イベント駆動型システムとして設計されており、通知を非同期に処理することで、毎秒50,000リクエストを処理し、配信の99%で2秒未満のレイテンシを実現します。アーキテクチャは、関心の分離が明確なマイクロサービスパターンに従っています。

高レベルアーキテクチャ

イベントソース → APIゲートウェイ → 通知サービス → メッセージキュー → デリバリーワーカー
                                      ↓
                            プリファレンスサービス
                                      ↓
                            キャッシュレイヤー (Redis)...
全文を表示

スケーラブルな通知サービスアーキテクチャ

システム概要

通知サービスは、分散型イベント駆動型システムとして設計されており、通知を非同期に処理することで、毎秒50,000リクエストを処理し、配信の99%で2秒未満のレイテンシを実現します。アーキテクチャは、関心の分離が明確なマイクロサービスパターンに従っています。

高レベルアーキテクチャ

イベントソース → APIゲートウェイ → 通知サービス → メッセージキュー → デリバリーワーカー
                                      ↓
                            プリファレンスサービス
                                      ↓
                            キャッシュレイヤー (Redis)
                                      ↓
                            データベース (PostgreSQL)

主要コンポーネント

1. APIゲートウェイ

  • 責務: すべての通知リクエストのエントリポイント。レート制限、認証、リクエスト検証を処理します。
  • テクノロジー: NGINX または AWS API Gateway
  • 根拠: 単一のエントリポイントを提供し、過負荷を防ぐためのリクエストスロットリングを可能にし、バックエンドサービス全体にトラフィックを分散させます。

2. 通知サービス(コア処理)

  • 責務: 通知イベントを受信し、検証し、ユーザー設定でエンリッチし、メッセージキューに発行します。
  • テクノロジー: ステートレスマイクロサービス (Node.js, Go, または Java)
  • 主要機能:
    • 通知ペイロードを検証する
    • キャッシュからユーザー設定を取得する
    • ユーザー設定に基づいて通知チャネル(プッシュ、アプリ内、メール)を決定する
    • エンリッチされた通知をメッセージキューに発行する
  • スケーラビリティ: 水平スケーラブル。ロードバランサーの後ろに複数のインスタンスがあります。

3. メッセージキュー(イベントバス)

  • テクノロジー: Apache Kafka または AWS SQS/SNS
  • 根拠:
    • 通知生成と配信を分離する
    • 少なくとも1回の配信保証のための耐久性と再生機能を提供する
    • 通知の並列処理を可能にする
    • リクエストをバッファリングすることでトラフィックスパイクを処理する
  • 設定: 並列消費を可能にするための複数のパーティション(例:100〜200)
  • トピック構造: プッシュ、アプリ内、メール通知ごとに個別のトピックがあり、独立したスケーリングが可能

4. プリファレンスサービス

  • 責務: ユーザーの通知設定と設定を管理します。
  • テクノロジー: PostgreSQLバックエンドを持つマイクロサービス
  • 機能:
    • ユーザー設定(通知タイプ、チャネル、頻度制限)を保存する
    • ユーザーが設定を更新するためのAPIを提供する
    • 高速アクセス用にRedisに設定をキャッシュする
  • スケーラビリティ: 読み取り負荷の高いサービス。キャッシングによりデータベースの負荷が大幅に軽減されます。

5. キャッシュレイヤー

  • テクノロジー: Redis Cluster
  • 目的:
    • ユーザー設定をキャッシュする(TTL:1時間)
    • プッシュ通知用のユーザーデバイスートークンをキャッシュする
    • レート制限カウンターを保存する
    • データベースクエリを90%以上削減する
  • 根拠: 設定ルックアップのためのサブミリ秒レイテンシ

6. デリバリーワーカー

  • プッシュ通知ワーカー:

    • プッシュトピックから消費する
    • FCM(Firebase Cloud Messaging)およびAPNs(Apple Push Notification service)と統合する
    • デバイスートークン管理と無効なトークンのクリーンアップを処理する
    • リトライのために指数バックオフを実装する
  • アプリ内通知ワーカー:

    • アプリ内トピックから消費する
    • 通知を時系列データベース(例:CassandraまたはClickHouse)に保存する
    • WebSocketサーバーに発行してリアルタイム配信する
    • 通知の既読/未読ステータスを維持する
  • メール通知ワーカー:

    • メールトピックから消費する
    • 効率化のためにメールをバッチ処理する
    • メールサービス(SendGrid、AWS SES)と統合する
    • スパムフィルターを回避するためにレート制限を実装する

7. WebSocketサーバー

  • 責務: モバイルおよびWebクライアントとの永続的な接続を維持し、リアルタイムのアプリ内通知を配信します。
  • テクノロジー: Socket.io を使用した Node.js または gorilla/websocket を使用した Go
  • スケーラビリティ: ステートレスサーバー。サーバー間通信のためにRedis pub/subを使用します。
  • フォールバック: WebSocketをサポートしないクライアントのためのHTTPロングポーリング

8. 通知ストア(時系列データベース)

  • テクノロジー: Cassandra または ClickHouse
  • 目的: 監査、分析、ユーザー通知履歴のためにすべての通知を保存する
  • 根拠: 書き込み負荷の高いワークロードと時間範囲クエリに最適化されている
  • 保持期間: 90日間の通知履歴

9. ユーザーデバイスレジストリ

  • テクノロジー: Redis + PostgreSQL
  • 目的: ユーザーとデバイスおよびプッシュートークンのマッピングを維持する
  • 機能:
    • デバイスの登録/登録解除を追跡する
    • デバイスメタデータ(OS、アプリバージョン)を保存する
    • トークンの更新と無効化を処理する

データフロー

  1. イベント取り込み: イベントソース(ユーザーアクション、システムイベント)がAPIゲートウェイに通知リクエストを送信します。
  2. 検証とエンリッチメント: 通知サービスがペイロードを検証し、キャッシュからユーザー設定を取得します。
  3. チャネル決定: 設定に基づいて、通知が適切なトピック(プッシュ、アプリ内、メール)にルーティングされます。
  4. キューイング: メッセージキューが通知をバッファリングし、耐久性を保証します。
  5. 配信: 専用ワーカーがトピックから消費し、それぞれのチャネル経由で配信します。
  6. 確認: デリバリーワーカーが正常な配信を確認し、通知ステータスを更新します。

要件の達成

スケーラビリティ(毎秒50,000リクエスト)

  • 水平スケーリング: すべてのコンポーネントはステートレスで水平スケーラブルです。
  • メッセージキューのパーティショニング: Kafkaトピックは複数のブローカーにパーティション化されています。各パーティションは毎秒約500〜1000リクエストを処理できます。
  • データベースシャーディング: ユーザーデータはuser_idでシャーディングされ、負荷を分散します。
  • キャッシング戦略: Redisがホットデータをキャッシュし、データベースクエリを90%以上削減します。
  • ロードバランシング: APIゲートウェイが通知サービスインスタンス全体にトラフィックを分散します。

低レイテンシ(99%が2秒以内)

  • 非同期処理: 通知は非同期に処理され、APIはキューイング後すぐに返却されます。
  • キャッシング: ユーザー設定はRedisにキャッシュされています(サブミリ秒アクセス)。
  • 直接統合: プッシュワーカーは、中間ホップなしでFCM/APNsと直接統合します。
  • アプリ内のWebSocket: 永続的な接続を介したリアルタイム配信。
  • 最適化: メール通知のバッチ処理(メールユースケースでは許容範囲)。
  • 監視: 各コンポーネントのレイテンシを追跡し、低下した場合にアラートを発します。

信頼性(少なくとも1回の配信)

  • メッセージキューの耐久性: Kafkaはメッセージをブローカー間でレプリケートします(レプリケーションファクター:3)。
  • 永続キュー: メッセージは確認前にディスクに永続化されます。
  • 冪等性: 通知には一意のIDが含まれており、ワーカーは冪等な処理を実装します。
  • リトライロジック: 失敗した配信は指数バックオフでリトライされます(最大5回、24時間以内)。
  • デッドレターキュー: 最大リトライ後に失敗した通知は、手動調査のためにDLQに移動されます。
  • 監視とアラート: リアルタイムダッシュボードが配信成功率を追跡し、失敗時にアラートを発します。
  • バックアップとリカバリ: 設定データと通知データの定期的なバックアップ。災害復旧手順。

パーソナライゼーション

  • プリファレンスサービス: ユーザー通知設定を管理する専用サービス。
  • 詳細な制御: ユーザーは通知をタイプ別(いいね、コメント、フォロー)およびチャネル別に無効にできます。
  • 頻度制限: 日次/週次ダイジェストオプションのサポート。
  • サイレントアワー: ユーザーはサイレントアワーを設定できます(例:午後10時から午前8時まではプッシュ通知なし)。
  • キャッシュ無効化: 設定変更はキャッシュを即座に無効化し、リアルタイムの効果をもたらします。

技術選択とトレードオフ

| コンポーネント | テクノロジー | 根拠 | トレードオフ |
|---|---|---|---|
| メッセージキュー | Kafka | 高スループット、耐久性、再生機能 | オペレーションの複雑さ、クラスター管理が必要 |
| キャッシュ | Redis Cluster | サブミリ秒レイテンシ、複雑なデータ構造をサポート | メモリバウンド、慎重なエビクションポリシーが必要 |
| プリファレンスDB | PostgreSQL | ACID準拠、複雑なクエリ、成熟したエコシステム | 垂直スケーリングの限界、リードレプリカが必要 |
| 通知ストア | Cassandra | 書き込み最適化、分散型、時系列データを処理 | 結果整合性、複雑なオペレーションモデル |
| プッシュ統合 | FCM/APNs | 業界標準、高信頼性 | ベンダーロックイン、プロバイダーごとのレート制限 |
| WebSocket | Socket.io/gorilla | リアルタイム通信、フォールバックサポート | 接続ごとのメモリオーバーヘッド、スティッキーセッションが必要 |

オペレーション上の考慮事項

監視とオブザーバビリティ

  • メトリクス: 通知スループット、レイテンシパーセンタイル(p50、p95、p99)、配信成功率。
  • ロギング: 相関ID付きの構造化ロギングによるエンドツーエンドトレーシング。
  • 分散トレーシング: リクエストフローの可視化のためのJaegerまたはZipkin。
  • アラート: クリティカルな障害のためのPagerDuty統合。

デプロイとスケーリング

  • コンテナ化: すべてのサービスのためのDockerコンテナ。
  • オーケストレーション: 自動スケーリングとデプロイのためのKubernetes。
  • 自動スケーリング: CPU/メモリとキューの深さに基づくHorizontal Pod Autoscaler。
  • ブルーグリーンデプロイメント: サービス更新のためのゼロダウンタイムデプロイメント。

コスト最適化

  • 予約済み容量: 予約インスタンス上のKafkaブローカーとデータベースインスタンス。
  • 階層型ストレージ: Redisにホットデータ、PostgreSQLにウォームデータ、S3にコールドデータ。
  • バッチ処理: APIコールを削減するためのメール通知のバッチ処理。
  • リソース制限: リソース枯渇を防ぐためのユーザーごとのレート制限。

潜在的なボトルネックと緩和策

  1. データベースのボトルネック: プリファレンスルックアップ。

    • 緩和策: Redisキャッシング(1時間TTL)、PostgreSQLのリードレプリカ。
  2. メッセージキューのボトルネック: Kafkaのスループット。

    • 緩和策: パーティション数の増加、ブローカーハードウェアのアップグレード、圧縮の使用。
  3. プッシュサービスのレート制限: FCM/APNsの制限。

    • 緩和策: リクエストキューイングの実装、リクエストのバッチ処理、複数のサービスアカウントの使用。
  4. WebSocket接続制限: サーバーあたりの接続制限。

    • 緩和策: 水平スケーリング、接続プーリング、サーバー間のロードバランシング。

結論

このアーキテクチャは、毎秒50,000リクエストを処理し、通知の99%で2秒未満の配信を維持できる、スケーラブルで信頼性が高く、低レイテンシの通知サービスを提供します。非同期処理、メッセージキュー、キャッシングの使用により、パフォーマンスと信頼性の両方が保証されます。モジュラー設計により、コンポーネントの需要に応じた独立したスケーリングが可能になり、包括的な監視により運用上の可視性が確保されます。システムは、リトライロジック、デッドレターキュー、冗長性を通じて障害を適切に処理し、少なくとも1回の配信セマンティクスを保証します。

判定

2位

勝利票

0 / 3

平均スコア

75
採点モデル OpenAI GPT-5.4

総合点

73

総評

回答Bは、APIゲートウェイ、キュー、プリファレンスサービス、キャッシュ、ワーカー、WebSocket配信など、通知サービスに期待される主要な構成要素を備えた、妥当なイベント駆動型設計を提供しています。スケーラビリティ、レイテンシ、信頼性について、まずまずの高いレベルで対処しており、いくつかの実装上の選択肢や運用上の注意点も含まれています。しかし、より一般的であり、エンドツーエンドのフローの詳細が少なく、重複排除セマンティクス、通知永続化の順序付け、大規模なファンアウト処理、ホットパーティション、リプレイ、障害発生時の損失保証の正確なメカニズムといった困難な問題の扱いが弱いという欠点があります。また、通知履歴にClickHouseを使用したり、KafkaとSQS/SNSを混在させたりするなど、技術的な選択肢の一部は正当性が低かったり、わずかに不適切であったりします。

採点詳細を表示

設計の質

重み 30%
72

アーキテクチャには期待される主要コンポーネントと妥当な非同期フローが含まれていますが、より一般的であり、いくつかの重要な構造的詳細が省略されています。永続化の境界、リプレイパス、または障害発生時のコンポーネント間の連携方法が完全に指定されていないため、設計はそれほど堅牢ではなく、深く検討されていないように感じられます。

完全性

重み 20%
74

主要なプロンプト要件をカバーし、有用な運用トピックも追加していますが、いくつかの領域は軽く扱われているだけです。特に、大規模なファンアウトイベント、詳細な配信状態モデリング、より強力な損失保証、永続化と配信の間の相互作用については、十分な深さで検討されていません。

トレードオフの説明力

重み 20%
70

トレードオフの表といくつかの根拠があり役立ちますが、その根拠は比較的表面的です。KafkaやSQS/SNSを区別なく使用するなど、一部の選択肢は広すぎるか曖昧に提示されており、この設計で重要な意味を持つセマンティックな違いについては議論されていません。

拡張性・信頼性

重み 20%
73

水平スケーリング、パーティション、リトライ、DLQに対処しているため、方向性は正しいです。しかし、信頼性の扱いはそれほど厳密ではありません。確認の境界、冪等な書き込み、順序付け、リプレイ、障害処理は、この規模で損失なしおよび少なくとも1回という要件を完全に正当化するには、具体性に欠けています。

分かりやすさ

重み 10%
82

回答は読みやすく、適切にセクション分けされており、スキャンしやすいです。フォーマットはアクセシビリティを向上させていますが、その明瞭さの一部は技術的な深さと正確性を犠牲にしています。

総合点

80

総評

回答Bは、明確で整理されたシステム設計を提示しています。ハイレベルな図、箇条書き、専用のトレードオフ表の使用により、可読性が向上しています。すべてのコア要件を効果的にカバーしていますが、複雑なシナリオに対する詳細の深さとソリューションの洗練度は、回答Aほど顕著ではありません。堅実ではありますが、回答Aに存在する高度な考慮事項がいくつか欠けています。

採点詳細を表示

設計の質

重み 30%
80

回答Bは、明確なハイレベルアーキテクチャと役立つ図を提供しています。しかし、「通知サービス」のような一部のコンポーネントは回答Aよりも粒度が低く、複雑なファンアウトシナリオの処理に関する詳細が少ないです。

完全性

重み 20%
80

回答Bはすべてのコア要件をカバーしていますが、特定の側面(例:具体的な冪等性メカニズムや高度なファンアウトの考慮事項)に関する詳細の深さは、回答Aと比較してそれほど広範ではありません。

トレードオフの説明力

重み 20%
75

回答Bは、技術選択とそのトレードオフに関する明確な表を提供しており、よく提示されています。しかし、トレードオフは主に選択された技術の長所と短所に焦点を当てており、広範なシステム設計への影響については回答Aほど深くありません。

拡張性・信頼性

重み 20%
82

回答Bは、水平スケーリング、Kafkaパーティショニング、DBシャーディング、キャッシング、リトライ、DLQに言及しており、スケーラビリティと信頼性について良好なカバレッジを提供しています。しかし、回答Aに見られるような詳細な実装の詳細や特定の戦略がいくつか欠けています。

分かりやすさ

重み 10%
90

回答Bは、見出し、箇条書き、ハイレベルな図、専用のトレードオフ表を利用しており、非常に明確で整理されています。「要件の満たし方」セクションは、明確さと直接性の点で特に効果的です。

総合点

71

総評

回答Bは、明確な見出し、図のスケッチ、トレードオフ表を備え、整理されており、読みやすいです。主要なコンポーネント(APIゲートウェイ、Kafka、Redis、ワーカー、WebSocket、Cassandra)を網羅し、各要件に明示的に対応しています。しかし、設計は表面的であり、セレブリティユーザーに対するファンアウト増幅、パーティショニング戦略、ホットキー処理、WebSocketノード間でのプレゼンスルーティング、または冪等性キー設計のニュアンスについては真剣に取り組んでいません。トレードオフは表形式で提示されていますが、深みに欠けます。この規模でのプリファレンスに対するPostgreSQLは、キーと値のアクセスパターンを考えると、強力な正当化なしに言及されています。

採点詳細を表示

設計の質

重み 30%
70

すべての期待されるコンポーネントが明確に特定された、堅実な標準アーキテクチャですが、扱いは教科書レベルに近いです。ファンアウト増幅、パーティションホットキー、WebSocketノード間のプレゼンス/接続ルーティングに関する深みに欠けています。

完全性

重み 20%
75

すべての主要コンポーネントを網羅し、各要件に明示的に対応しています。さらに、デプロイメント、コスト、ボトルネックなどの運用上の懸念も含まれています。テンプレート/レンダリングサービスと詳細なファンアウト処理が欠けています。

トレードオフの説明力

重み 20%
65

テクノロジーごとの長所と短所をリストしたトレードオフ表を提供していますが、理由は簡潔で一般的です。この規模でのプリファレンスに対するPostgreSQLの選択や、配信セマンティクスのトレードオフに関する議論を深く正当化していません。

拡張性・信頼性

重み 20%
70

レプリケーションファクター、バックオフ付きリトライ、DLQ、冪等性、水平スケーリングに対処していますが、扱いはハイレベルです。定量的な主張(例:パーティションあたり500〜1000 req / sec、キャッシュ削減率90%)は、ニュアンスなしに断言されています。

分かりやすさ

重み 10%
80

見出し、箇条書き、図のスケッチ、トレードオフ表の優れた使用により、設計のナビゲーションとレビューが容易になっています。

比較結果サマリー

最終順位は、採点者ごとの順位集約(平均順位 + ボルダ方式の同点処理)で決定します。平均点は参考表示です。

採点者数: 3

勝利票

3 / 3

平均点

89
この回答を見る

採点結果

勝者理由

回答Aは、ファナウトシャーディング、ホットパーティション、ハイブリッドファナウトオンライト/リード、冪等性キーの構築、プレゼンスルーティングなどの、明白ではないシステム設計上の課題に対する実質的に深い関与により、最も重み付けの高い基準(アーキテクチャ品質30%、トレードオフの推論20%)で勝利します。回答Bは視覚的な明瞭さとフォーマットが優れていますが、その技術的な深さは浅く、これらのフォーマット上の利点は、与えられた重み付けの下でのAの優れたアーキテクチャ推論を上回るものではありません。

勝者理由

回答Aは、システム設計における優れた深さ、詳細さ、包括的なアプローチにより勝利しました。より詳細なアーキテクチャコンポーネントを提供し、ファンアウト(セレブリティユーザー向け)のような複雑なエッジケースに対処し、単なる技術選択を超えたトレードオフに関するより深い議論を提供しています。回答Bは明確でよく構成されていますが、回答Aは、高スケーラブルで信頼性の高い通知サービスを設計するシニアソフトウェアエンジニアに期待される、より高度な専門知識を示しています。

採点モデル OpenAI GPT-5.4

勝者理由

回答Aは、最も重要な基準であるアーキテクチャ品質、完全性、トレードオフの推論、スケーラビリティ/信頼性において、加重された強みが著しく高いため、勝利します。より現実的なシステム分解を示し、障害シナリオでのコンポーネントの相互作用を説明し、少なくとも1回配信、冪等性、永続性、キューイング、ファンアウト、低レイテンシパス、および運用回復に関する深い理解を示しています。回答Bは堅実ですが、テンプレート的であり、プロンプトで要求される困難な設計側面に関する厳密さが欠けています。

X f L