ブログ一覧

SQS・Pub/Sub・Azure Service Bus比較:配送保証・順序・再処理で選ぶ

· 約11分で読めます

AWSのSQSとSNS、Google Cloud Pub/Sub、Azure Service Busを、仕事の分配とイベント配信、重複排除、順序、滞留、DLQからの復旧で比較。exactly-onceの範囲と業務の二重処理を分けて設計します。

SQS・Pub/Sub・Service Bus:仕事の分配とイベントの配信を分ける

注文が確定したら発送と分析へ知らせたいとします。発送担当のworkerが10台あっても、発送という仕事はそのうちの1台が担えば十分です。一方、分析にも同じ注文確定を渡すなら、発送と分析は別々に受け取る必要があります。この二つを、競合するconsumerによる分担と、fanoutによる配信として区別します。

目的AWSGoogle CloudAzure
発送worker同士で分担1つのSQSキューを複数consumerで受信1つのサブスクリプションを複数subscriberで受信Service Busの1つのキューを複数receiverで受信
発送と分析へそれぞれ配信SNS topicから業務ごとに分けたSQSキューへ配信Pub/Sub topicに業務ごとのサブスクリプションService Bus topicに業務ごとのサブスクリプション

発送と分析のworkerを同じ分担用キューやサブスクリプションへ混ぜると、両方にすべてのイベントが渡る構成になりません。業務ごとに滞留と再試行を分け、分析が遅れても発送を止めない構成にします。追加の購読先が増えれば、配送・保持・consumerの費用も増えます。

重複排除とexactly-onceは、何を一度にするのか

機能・方式確認できる範囲別に設計すること
SQS Standard少なくとも1回の配送。重複や順序の入れ替わりがあり得る再配送されても同じ業務操作を二重に実行しない
SQS FIFOの送信重複排除同じ重複排除ID等による5分間の送信再試行の重複を抑える期限後の再送と、処理後・削除前の停止による再処理
Pub/Subのexactly-once delivery有効化したpull方式で、リージョン内の保証。成功確認済みのack後に再配送しないpush・exportへの適用は不可。ack期限切れ等の有効な再配送と外部副作用
Service Busのduplicate detection有効化したStandard・Premiumで、設定窓内の送信IDを重複排除受信処理の再実行と外部副作用。partition利用時はPartitionKeyも確認

Service Busの重複検出窓は20秒〜7日で設定でき、既定は10分です。Pub/Subの保証も、同じ業務イベントをpublisherが別メッセージとして二度発行したことまで同一視するものではありません。どの場合も、発送APIの成功直後にconsumerが停止すれば、配送サービスだけでは発送済みかを判断できません。

仮定の発送処理:配送保証の外にある副作用を、元の発送操作IDで照合する
  1. メッセージ基盤: ship-123を渡す
  2. 配送業者API: 発送依頼が成功
  3. worker: 結果保存・受領確定の前に停止
  4. メッセージ基盤: 期限切れ等で再配送
  5. 配送業者API: 同じship-123で結果照合・重複対策

注文保存と配信の間はOutbox、受信側は業務操作IDで守る

DBへ注文を保存した後、メッセージ送信前に落ちると、発送へ何も届きません。注文とoutboxのイベントを同じDBトランザクションへ保存し、リレーやCDCで送信する方式を検討します。未送信イベントの保持、リレーの再起動、再試行、最古の未送信時刻を管理します。送信成功後の記録に失敗すれば再送されるので、受信側の重複対策も必要です。

順序は注文単位か、顧客単位かを先に決める

候補順序の単位・条件並列性への影響
SQS FIFOMessageGroupId内の順序異なるグループは並列化し、同じグループの処理順をconsumer側でも守る
Pub/Subのordering有効化した購読で同じordering key。発行は同一リージョンへキーをまたぐ全体順序ではない。遅いキーを分離して測る
Service Bus sessionsStandard・Premiumで同じSessionIdセッション単位で受信し、ロック更新・期限切れを扱う

すべてを1つのキーへ寄せると、遅い注文が全体の進行を止める原因になります。注文の作成→変更→取消の順序が必要なら注文IDでまとめ、必要な並列性を残します。ただし到着順が業務上の正しい順序とは限らないため、イベントの版や現在の状態も照合します。DLQへ隔離して後で戻すときの順序も別に決めます。

滞留と費用は、再試行・購読先・下流上限まで含める

仮に到着が毎秒900件、実際に成功する処理能力が毎秒700件の状態が10分続くと、滞留は(900 − 700) × 600 = 120,000件です。その後の到着が毎秒500件なら余力は毎秒200件なので、一定流量の仮定では解消に120,000 ÷ 200 = 600秒、つまり10分かかります。workerを増やしても配送業者APIの上限が毎秒700件なら、それ以上の成功処理能力にはなりません。

DLQは未完了の仕事:安全な再投入を採用条件にする

失敗したメッセージをDLQへ送っても、発送は完了していません。たとえば配送業者の受付後に結果保存が失敗したなら、原因を直して全件再投入するだけでは二重発送になり得ます。SQSのredriveでは新しいmessageIDが付くため、元の発送操作IDで成功済みかを調べます。各社でも、再処理でIDと期限がどう扱われるかを確認します。

  1. 担当と通知先、保存期限、調査に必要な業務操作IDを決める。通常キューが空でもDLQに未完了が残っていないかを見る。
  2. 原因と既存の副作用を照合し、成功済みなら結果を修復する。期限切れや順序違反になる操作は、通常の再投入から外して判断する。
  3. 必要な仕事だけを少量・低速で戻し、通常処理の遅延と下流のエラーを見て増やす。中止条件も定める。
  4. 副作用直後、受領確定直前、ロック期限切れで停止させ、二重処理と処理漏れを業務結果で検査する。これを満たす構成同士で運用負荷と費用を比べる。

配送・順序・重複排除の範囲を確認する一次資料

この記事で深掘りしたTips