代表的な面接トピック

システムデザイン面接:CloudEvents取り込みゲートウェイの設計

システム設計難しい
Offer.cc 編集チーム公開日 更新日

質問

HTTP経由でCloudEventsを受け入れ、イベントを失うことなく、またビジネス上の影響を重複させることなく内部コンシューマーにルーティングするマルチテナントゲートウェイを設計してください。

プロンプトと前提条件

プロデューサーは、リトライ、バージョニングされたペイロード、不均一なトラフィックを伴ってCloudEventsを送信します。ゲートウェイはエンベロープを検証し、テナントを分離し、配信の証跡を保持し、少なくとも1回(at-least-once)の動作をコンシューマーに対して明示的にする必要があります。

面接官がテストするポイント

  • プロトコルエンベロープを明確な取り込みおよび配信コントラクトに変換できるか。
  • 冪等性のスコープ、リトライ状態、および永続的なハンドオフ境界を適切に選択できるか。
  • テナント分離、スキーマの進化、および運用上の証跡を設計できるか。

回答前に明確にすべき質問

  • 各テナントがサポートする必要があるピーク時の秒間イベント数(EPS)とペイロードサイズはどれくらいか?
  • プロデューサーは無期限にリトライすることが許可されているか、またソース(source)またはサブジェクト(subject)ごとの順序保証は必要か?
  • どのコンシューマーが少なくとも1回の配信を必要とし、ソースとIDによる重複排除が可能か?
  • スキーマは一元的に登録されているか、またリプレイ用に生イベントをどのくらいの期間保持する必要があるか?

30秒の回答フレームワーク

認証されたエッジでTLSを終端し、CloudEventsエンベロープとテナントのクォータを検証した上で、確認応答(ack)を返す前に生イベントを永続的に追加します。パーティション化されたキューが、少なくとも1回の配信を使用してコンシューマーにファンアウトします。プロデューサーがその安定性を保証している場合、(tenant, source, id)が重複排除キーとなります。コンシューマーの確認応答、リトライスケジュール、デッドレター、スキーマバージョン、およびテナントごとの制限により、損失や重複が暗黙的ではなく可視化されます。

ステップごとの詳細解説

1. 取り込みと検証

構造化またはバイナリのHTTPバインディングを受け入れ、サイズとコンテンツタイプの制限を適用し、specversiontypesourceidなどの必須属性を検証します。テナントを認証し、永続化処理の前に無効なエンベロープを拒否します。監査とリプレイのために、受信した正確なバイト列とヘッダーを保持します。

2. 永続化の境界を選択する

成功を返す前に、1回の永続的な操作で不変のイベントレコードとアウトボックスまたはログオフセットを書き込みます。キューのみの確認応答では、キューへのパブリッシュがコミットされていない場合にイベントが失われるリスクがあります。データベースのみの設計では、大量のファンアウトでボトルネックになる可能性があります。レイテンシと耐久性のトレードオフを明確に述べてください。

3. リトライを隠さずに重複排除する

プロデューサーのリトライをカバーする保持期間を設定し、テナントスコープの(source, id)キーを使用します。ペイロードのダイジェストとスキーマバージョンを保存します。同じキーで異なるバイト列の場合は、隔離(quarantine)が必要な競合となります。リトライが観測可能な状態を維持できるよう、配信試行と論理イベントを分離して保持します。

4. 配信とリトライ

コンシューマーはパーティションからプルするか、リース付きでプッシュ配信を受け取ります。確認応答が成功すると試行が進みます。タイムアウトや一時的な障害が発生した場合は、ジッターを伴う指数バックオフ(exponential backoff)をスケジュールします。永続的な障害は、リプレイ制御と監査ログを備えたテナントスコープのデッドレターストリームに移動します。

5. 進化と運用

取り込み時にスキーマバージョンを検証し、互換性のないイベントを隔離環境にルーティングし、コンシューマーの機能宣言をサポートします。承認、拒否、重複、遅延、リトライ、デッドレター化、リプレイされたイベントをテナントおよびソースごとに測定します。シークレットや無制限のペイロードをログに記録することなく、クォータ、暗号化、保持期間、およびアクセス制御を適用します。

質の高い模範解答

「エッジで各テナントを認証し、CloudEventsエンベロープを検証し、サイズとクォータの制限を適用した上で、確認応答を返す前に正確なイベントとヘッダーを永続的に追加します。その後、パーティション化されたログが少なくとも1回配信します。重複排除キーは、プロデューサーがIDの安定性を保証している場合は『テナント+ソース+ID』とし、同じキーでダイジェストが変更された場合は隔離します。コンシューマーは試行を確認応答し、一時的な障害はジッター付きでバックオフし、永続的な障害はリプレイ可能なデッドレターストリームに送られます。スキーマバージョン、テナントごとのメトリクス、保持期間、監査ログにより、配信セマンティクスを明示的にします。」

よくある間違い

  • 永続的な追加の前に確認応答を返す → クラッシュによりイベントが失われる → 選択した永続化境界の後にackを返す。
  • グローバルにIDで重複排除する → テナントまたはソースが衝突する可能性がある → キーのスコープを限定し、ダイジェストを検証する。
  • 正確に1回(exactly-once)を約束する → リトライやコンシューマー側の副作用は依然として発生し得る → 少なくとも1回(at-least-once)を明示し、冪等なコンシューマーを要求する。
  • 互換性のないスキーマを破棄する → デバッグとリプレイが不可能になる → バージョニングされた証跡とともに隔離する。

フォローアップ質問と回答

ゲートウェイは順序を保証できますか?

ソースとサブジェクトのパーティションなど、定義されたスコープ内でのみ可能です。シーケンスメタデータを保持し、同じキーを1つのパーティションにルーティングし、リトライや並列コンシューマーによって後続のイベントが遅延する可能性があることを文書化します。

プロデューサーが異なるペイロードに対して同じIDを再利用した場合はどうなりますか?

保存されているダイジェストと比較し、競合を拒否または隔離します。最初のイベントを警告なしに上書きしてはなりません。重複排除コントラクトが破られているため、プロデューサーにアラートを通知します。

テナント固有のリプレイをどのようにサポートしますか?

認可にバインドされたリプレイトークン、新しい試行ID、レート制限、および監査証跡を備えた不変のイベントレコードを保持します。リプレイはスキーマおよび重複排除のチェックを通過する必要があり、テナント分離をバイパスしてはなりません。

公開情報ソース

関連する質問

関連面接ツール

システム設計の回答には「回答する」を使用

まず要件を明確にし、スケール、アーキテクチャ、コンポーネント選定、トレードオフの順に進めます。

ツールを見る