代表的な面接トピック

バックエンド面接:SQS FIFOの重複排除は実際に何を保証するのか?

バックエンド難しい
Offer.cc 編集チーム公開日 更新日

質問

Amazon SQS FIFOでMessageDeduplicationIdを使用する場合、5分間の重複排除インターバルは何を保証しますか?処理後かつメッセージ削除前にコンシューマがクラッシュした場合、重複したビジネス上の副作用をどのように防ぎますか?

プロンプトとコンテキスト

この質問は、バックエンド、プラットフォーム、分散システムの面接に適しています。面接官はその境界線を求めています。つまり、SQSは重複排除インターバル内において同一の重複排除IDを重複として扱い、メッセージが受信および削除された後もそのIDの追跡を維持しますが、外部データベース、決済、メール送信などの副作用が本質的に厳密に1回(exactly-once)になるわけではありません。

面接官がテストしていること

優れた回答は、プロデューサー側の重複排除、FIFO順序保証、コンシューマの可視性タイムアウト、削除確認、ビジネス上のべき等性を明確に区別します。AWSは重複排除IDを重複配信を防ぐトークンと定義しています。コンテンツベースの重複排除が有効でIDが指定されていない場合、SQSはメッセージ本文をハッシュ化してIDを導出できます。回答では、「FIFOは絶対に重複しない」と言うのではなく、インターバル、リトライ、可観測性をカバーする必要があります。

最初に確認すべき明確化のための質問

セマンティクスの境界

要件がキューレベルの重複抑制なのか、少なくとも1回の処理(at-least-once)なのか、それとも1回限りのビジネス効果なのかを尋ねます。「1つのメッセージ」と「1回の請求」を明確に区別してください。

重複排除の入力

プロデューサーが一貫したMessageDeduplicationIdを生成しているか、コンテンツベースの重複排除が有効か、メッセージグループがどのように選択されているか、リトライが5分間のインターバル内に収まるかを確認します。

障害発生ポイント

受信、処理、副作用の書き込み、DeleteMessageのタイムラインを描きます。コンシューマのクラッシュ、可視性タイムアウト、ネットワークリトライ、ダウンストリームのタイムアウト時に何が起こるかを尋ねます。

30秒回答フレームワーク

「FIFOの重複排除IDは、5分間のインターバル中に同じメッセージが再び受け入れられるのを抑制し、そのIDの追跡を維持します。これはキューレベルの重複送信と順序付けに対処するものであり、外部への副作用の厳密に1回(exactly-once)の実行を保証するものではありません。私なら、べき等性レコードに安定したビジネスキーを使用し、副作用の状態とOutboxを単一のトランザクションまたは別のリトライセーフな境界内に配置し、成功後にのみメッセージを削除します。クラッシュによって再配信が発生する可能性はありますが、再試行時には完了済みレコードが読み取られます。」

ステップごとの詳細な回答

ステップ1: テスト可能な保証を明記する

5分間の重複排除インターバル中は同一の重複排除IDが重複として扱われ、SQSは受信および削除後もそのIDを追跡し続けることを説明します。このインターバルを永続的な重複排除として説明しないでください。

ステップ2: プロデューサーとコンシューマの制御を分離する

プロデューサーは1つのビジネスコマンドに対して安定したIDを使用します。コンテンツハッシュが機能するのは、本文がそのコマンドを完全に表している場合のみです。インターバル後のリトライでも同じビジネスアクションである可能性があるため、コンシューマには注文、支払いインテント、またはコマンドIDに対する永続的なユニーク制約が必要です。

ステップ3: クラッシュウィンドウをカバーする

コンシューマがデータベースに書き込んだ後にクラッシュした場合、可視性タイムアウト後にメッセージが再出現する可能性があります。副作用の状態とべき等性キーを1つのトランザクションに含めるか、再実行可能なパブリッシュのためにOutboxを使用し、コミットが成功した後にのみ削除します。

ステップ4: 順序付けとポイズンメッセージを処理する

順序が重要な場合は同じMessageGroupIdを使用し、処理内容に見合った可視性タイムアウトを設定します。リトライによってグループが永久にブロックされないよう、失敗を繰り返すメッセージは元のID、受信回数、失敗理由とともにデッドレターキュー(DLQ)に移動します。

ステップ5: 検証とオブザーバビリティ

プロデューサーのリトライ、書き込み後のコンシューマクラッシュ、DeleteMessageのタイムアウト、インターバル外の再再生をテストします。重複したビジネスキー、ApproximateReceiveCount、DLQの深さ、可視性タイムアウト、エンドツーエンドのレイテンシを監視します。アラートはキューの重複とビジネスの重複を区別できるようにする必要があります。

高品質な回答例

私はSQSの5分間の重複排除を、1回限りの支払いを保証するものではなく、トランスポート層のセーフガードとして扱います。プロデューサーは支払いインテントごとに安定したコマンドIDを作成し、リトライ時にもそれを再利用します。コンシューマはまずInboxテーブルで一意のコマンドIDを強制し、次に同じトランザクション内で注文状態とOutboxイベントを書き込み、コミット後にメッセージを削除します。書き込み後にプロセスがクラッシュしても、再配信時に完了済みレコードが検出されるため、二重請求は発生しません。重複コマンド、受信回数、DLQを監視し、ウィンドウ内、ウィンドウ外、DeleteMessageのリトライ時に障害を注入して検証します。

よくある間違い

  • 間違い: FIFOは永続的なexactly-onceを意味すると答える。 → なぜ失敗するか: 5分間のインターバルとコンシューマのクラッシュを無視しているため。 → 修正方法: IDの時間的境界を述べ、ビジネス上のべき等性を追加する。
  • 間違い: リトライごとに新しい重複排除IDを生成する。 → なぜ失敗するか: 1つのコマンドが複数のメッセージになってしまうため。 → 修正方法: 安定したコマンドIDを再利用する。
  • 間違い: 処理が完了する前に削除する。 → なぜ失敗するか: ダウンストリームの障害がメッセージ消失につながるため。 → 修正方法: コミット成功後に削除し、タイムアウトによる再配信を許容する。
  • 間違い: 本文のハッシュのみに依存する。 → なぜ失敗するか: タイムスタンプや無関係なフィールドによって重複排除がバイパスされる可能性があるため。 → 修正方法: ビジネスコマンドに対して明示的で安定したIDを定義する。

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

フォローアップ1: 同じコマンドが5分後に到着した場合はどうなりますか?

永続的なビジネスべき等性レコードを使用して完了したかどうかを判断します。キューの重複排除は短いウィンドウでの重複を減らしますが、長期的なビジネス状態を代替することはできません。

フォローアップ2: なぜ処理の前に削除しないのですか?

先に削除すると、ダウンストリームの障害がメッセージの消失につながります。消失が明示的に許容され、別のソースの信頼性が確保されていない限り、削除前にリトライを伴う処理を行う必要があります。

フォローアップ3: Outboxは何を解決しますか?

ビジネス状態と保留中のイベントを1つのデータベーストランザクションでコミットするため、安全にパブリッシュをリトライできます。ただし、ダウンストリームのコンシューマには依然としてイベントIDによるべき等性が必要です。

フォローアップ4: 二重請求が発生しないことをどのように証明しますか?

書き込み後、削除タイムアウト中、ウィンドウ外の再再生後に障害を注入します。キューのメトリクスだけに頼るのではなく、データベースの一意性制約、決済プロバイダーのべき等性キー、監査ログを検証します。

公開情報ソース

関連する質問