コンテンツに移動
データ分析

Cloud Pub/Sub、1 回限りの配信機能の一般提供を発表

2022年12月19日
Google Cloud Japan Team

※この投稿は米国時間 2022 年 12 月 2 日に、Google Cloud blog に投稿されたものの抄訳です。

本日、Google Cloud Pub/Sub チームは 1 回限りの配信機能の一般提供の開始を発表しました。この機能により、Pub/Sub のお客様は、クラウド リージョン内で 1 回限りの配信を受けることができ、以下の点が保証されます。

  • メッセージの確認応答が完了すると、再配信は発生しない。

  • メッセージが未処理の間、再配信は発生しない。メッセージは、確認応答期限が切れるか、確認応答が行われるまで、未処理とみなされます。

  • 確認応答の期限切れまたはクライアントによる否定確認応答により複数の有効な配信が存在する場合は、メッセージの確認応答に最新の確認応答 ID のみを使用できる。以前の確認応答 ID を持つリクエストは失敗します。

このブログでは、1 回限りの配信の基本、仕組み、ベスト プラクティス、機能制限について説明します。

重複

1 回限りの配信機能がなければ、お客様は重複配信を避けるために複雑なステートフル処理ロジックを独自に構築する必要があります。1 回限りの配信機能により、確認応答期限を過ぎていない間はメッセージを配信しないことがより強く保証されるようになりました。また、サブスクライバーによる確認応答の状態の検出が容易になり、その結果、メッセージをより簡単に 1 回限りで処理できるようになりました。まず、なぜ、どこに重複が発生するのかを理解しましょう。

Pub/Sub には、以下のような典型的なイベントの流れがあります。

  1. パブリッシャーは、トピックにメッセージをパブリッシュします。

  2. トピックは 1 つ以上のサブスクリプションを持つことができ、各サブスクリプションはトピックにパブリッシュされたすべてのメッセージを取得します。

  3. サブスクライバー アプリケーションは、Pub/Sub に接続してサブスクリプションから(pull または push 配信メカニズムによって)メッセージの受信を開始します。

このような基本的なメッセージング フローでは、重複が発生する可能性がある箇所が複数存在します。

パブリッシャー

  • パブリッシャーにネットワーク障害が発生し、Cloud Pub/Sub からの確認応答を受信できないことがあります。この場合、パブリッシャーはメッセージを再パブリッシュします。

  • パブリッシャー アプリケーションが、すでにパブリッシュされているメッセージの確認応答を受け取る前にクラッシュすることがあります。

サブスクライバー

  • サブスクライバーにメッセージの後処理でネットワーク障害が発生し、その結果、メッセージの確認応答を送信できないことがあります。この場合、メッセージはすでに処理されているにもかかわらず再配信されます。

  • サブスクライバー アプリケーションが、メッセージを処理した後、確認応答を送信する前にクラッシュすることがあります。この場合も、すでに処理されたメッセージの再配信が発生します。

Pub/Sub

  • Pub/Sub サービスの内部動作(例: サーバーの再起動、クラッシュ、ネットワーク関連の問題)により、サブスクライバーが重複してメッセージを受信することがあります。

有効な再配信と重複には明確な違いがあることに注意する必要があります。

  • 再配信は、メッセージに対してクライアントによる否定確認応答が行われた場合、または確認応答期限が切れる前にクライアントが確認期限を延長しなかった場合のいずれかのケースで発生します。再配信は有効な動作とみなされ、システムは意図したとおりに動作しています。

  • 重複とは、確認応答が成功した後、または確認応答期限が切れる前にメッセージが再送信された場合を指します。

1 回限りの配信機能の副作用

「副作用」とは、システムがローカル環境外の状態を変更する場合に使われる用語です。メッセージング システムのコンテキストでは、クライアントによって実行されているサービスが、メッセージング システムからメッセージを取り出し、外部システム(トランザクション データベース、メール通知システムなど)を更新することがこれにあたります。この機能は 1 回限りの配信機能の副作用を保証するものではなく、副作用は厳密にこの機能の範囲外であることを理解することが重要です。

たとえば、ある小売業者がお客様に一度だけプッシュ通知を送りたい場合を考えてみましょう。この機能は、メッセージはサブスクライバーに一度だけ送信され、メッセージの確認応答が正常に行われた後、または未処理の間は再配信が行われないことを保証します。サブスクライバーは、メール通知システムの 1 回限りの配信機能を活用し、メッセージが正確に一度だけお客様に push されるようにする必要があります。Pub/Sub には、副作用の配信を行うシステムに対して、接続性も制御機能もありません。そのため、Pub/Sub の 1 回限りの配信の保証と 1 回限りの配信の副作用を混同すべきではありません。

仕組み

Pub/Sub は、これまで一時メモリにしか保持されていなかった配信状態を、非常にスケーラブルな永続性レイヤに移行することでこの機能を実現しています。これにより、Pub/Sub は、配信が未処理の間は重複した配信が発生しないこと、また確認応答が行われた後は再配信が発生しないことをより確実に保証できるようになりました。配信の確認応答に使用される確認応答 ID はバージョン管理されており、最新バージョンのみ、配信の確認応答または確認応答期限の変更に使用できます。それ以前のバージョンの確認応答 ID を使用したリモート プロシージャ コールは失敗します。この内部の配信永続性レイヤの導入により、1 回限りの配信サブスクリプションは、通常のサブスクリプションと比較して、パブリッシュからサブスクライブまでのレイテンシが大きくなります。

https://storage.googleapis.com/gweb-cloudblog-publish/images/1_exactly-once_delivery.max-900x900.jpg

このことを例を使って理解しましょう。ここでは 1 つのパブリッシャーが、トピックにメッセージをパブリッシュしています。このトピックには 1 つのサブスクリプションがあり、それに対して 3 つのサブスクライバーがあります。

https://storage.googleapis.com/gweb-cloudblog-publish/images/2_exactly-once_delivery.max-900x900.jpg

ここで、subscriber#1 にメッセージ(青色)が送信されたとします。この時点でメッセージは未処理です。つまり Pub/Sub はメッセージを送信したものの、subscriber#1 はまだ確認応答を行っていません。メッセージを処理してから確認応答を行うのがベスト プラクティスであるため、これは非常に一般的なことです。メッセージは未処理なので、この新機能のおかげで、どのサブスクライバーにも重複して送信されることはありません。

1 回限りの配信のための永続性レイヤは、メッセージの配信のたびにバージョン番号を保存し、これはエンコードされて配信の確認応答 ID にも含められます。期限切れになっていないエントリが存在することは、すでに未処理の配信があり、メッセージを配信すべきではないことを示します(これにより、確認応答期限に関する保証が強化されます)。最新版を含まない確認応答 ID を使ってメッセージの確認応答または確認応答期限の修正を試みると、拒否されて確認応答リクエストに対して有用なエラー メッセージが返されることがあります。

例に戻ると、メッセージ M(青字)を subscriber#1 に配信するための配信バージョンが Pub/Sub の内部に格納されます(delivery#1 と呼ぶことにします)。これによって、メッセージ M の配信が未処理であることが追跡されます。subscriber#1 はメッセージの処理に成功し、確認応答(ACK#1)を送り返します。その後、メッセージは最終的に Pub/Sub から削除されます(トピックの保持ポリシーに従います)。

ここで、重複が発生する可能性のあるシナリオを考え、Pub/Sub の 1 回限りの配信機能が失敗をどのように防ぐかを考えてみましょう。

このシナリオでは、subscriber#1 がメッセージを取得し、データベース上の行をロックして処理します。この時点ではメッセージは未処理であり、Pub/Sub に確認応答は送信されていません。Pub/Sub は、配信バージョン管理メカニズムを通じて、ある配信(delivery#1)が subscriber#1 との間で未処理であることを検出します。

https://storage.googleapis.com/gweb-cloudblog-publish/images/3_exactly-once_delivery.max-1100x1100.jpg

この機能によって保証が強化されていなかった場合、メッセージが未処理の状態のまま、同一または別のサブスクライバー(subscriber#2)に再配信される可能性があります。これによって、subscriber#2 が更新のためにデータベースのロックを取得しようとすると、複数のサブスクライバーが同じ行のロックを取得しようとする結果となり、処理に遅延が発生します。

1 回限りの配信がこの状況を防ぎます。データ重複排除レイヤの導入により、Pub/Sub は期限が切れていない未処理の delivery#1 があることを検出し、該当するサブスクライバー(あるいは他のサブスクライバー)に同じメッセージを配信してはならないことを確認します。

1 回限りの配信の使用

Pub/Sub の重要な柱は「シンプルさ」であり、この機能も使いやすさを重視して設計されています。1 回限りの配信を行うサブスクリプションは、Google Cloud コンソール、Google Cloud CLI、クライアント ライブラリ、または Pub/Sub API を使用して作成できます。StreamingPull API を使用するサブスクライバーを含め、pull サブスクリプション タイプのみが 1 回限りの配信をサポートすることに留意してください。このドキュメントのセクションで、1 回限りの配信機能を備えた pull サブスクリプションを作成するための詳細な情報を提供しています。

この機能の効果的な使い方

  1. 機能を使いやすくするために、最新のクライアント ライブラリの利用をご検討ください。

  2. また、クライアント ライブラリでは、確認応答の有無を確認できる新しいインターフェースを使用することをおすすめします。応答の受信に成功すると、再配信が発生しないことが保証されます。具体的なクライアント ライブラリのサンプルはこちらです(C++、C#、Go、Java、Node.js、PHP、Python、Ruby)。

  3. ネットワークを原因とする確認応答の期限切れを減らすために、最小リース期間の延長設定を活用します: PythonNode.js、Go (MinExtensionPeriodin)

制限事項

  1. 1 回限りの配信はリージョンの機能です。つまり、提供される保証は、同じリージョンで実行されているサブスクライバーにのみ適用されます。1 回限りの配信を有効にしたサブスクリプションのサブスクライバーが複数のリージョンにある場合、重複が発生することがあります。

  2. 他のサブスクリプション タイプ(push と BigQuery)の場合、Pub/Sub はメッセージの配信を開始し、配信からの応答を確認応答として使用します。メッセージ受信者は、確認応答が実際に処理されたかどうかを知る方法がありません。一方、pull サブスクライバー クライアントは Pub/Sub に対して確認応答リクエストを開始し、Pub/Sub は確認応答が成功したかどうかで応答します。この配信動作の違いは、1 回限りの配信機能のセマンティクスは、pull 以外のサブスクリプションではうまく機能しないことを意味します。

1 回限りの配信機能の利用を開始するには、機能の詳細についてお読みいただくか、Cloud コンソールまたは gcloud CLI を使って、トピックに対して新しい pull サブスクリプションを作成してください。

参考情報

この機能について詳しくは、以下のリソースをご確認ください。


- Cloud Pub/Sub、テクニカル リード マネージャー、Mahesh Gattani
- Cloud Pub/Sub、シニア プロダクト マネージャー、Prateek Duble
投稿先