はじめに
最近、仕事で Google Cloud Pub/Sub を使用したシステムの構築に関わる機会がありました。この過程で、Pub/Sub のメッセージ配信の挙動や各種設定について学ぶことができました。
公式ドキュメントが最も信頼できる情報源ですが、その内容を自分なりにメモとしてまとめて残しておくことを目的としています。
送信回数の制御と Exactly-once delivery
Pub/Sub はデフォルトではメッセージの送信は at least once です。つまり、同じメッセージを重複して送信する可能性があります。したがって、デフォルトではSubscriber側では冪等性を保った処理を実装する必要があります。
By default, Pub/Sub offers at-least-once delivery with no ordering guarantees on all subscription types.
ref: Subscription overview | Cloud Pub/Sub Documentation | Google Cloud
メッセージの重複を排除し、同時に必ず一通のメッセージのみ送信したい場合は Exactly-once delivery という機能を利用できます。これは、一意のメッセージIDによって、ack前に重複したメッセージが送信されることを防ぎます。
Pub/Sub supports exactly-once delivery, within a cloud region, based on a Pub/Sub-defined unique message ID.
ref: Exactly-once delivery | Cloud Pub/Sub Documentation | Google Cloud
ただし、この機能はメッセージが「重複して」送られないようにするだけであり、「再送」は依然として行われます。英語ではそれを redelivery (再送) and duplicate (重複) という言葉で使い分けています
メッセージ順序と Message Ordering
Pub/Sub はデフォルトではメッセージの順序を保証しません。これは必ずしもPublishした順にSubscriberがメッセージを受け取るとは限らないことを示します。
メッセージの順序を保証したい際は、Message Ordering という機能があります。
Message ordering is a feature in Pub/Sub that lets you receive messages in your subscriber clients in the order that they were published by the publisher clients.
Message Orderingを有効化するには、トピックでこの機能を設定し、メッセージにユニークなキーを割り当てる必要があります。このキーは ordering key と呼ばれ、Pub/Subにメッセージを同じ順序で処理させたいグループを識別するために使用されます。メッセージが同一のキーで送信されると、Pub/Subはそのキーに基づいてメッセージを順番に配信します。
この機能の利用時にはいくつか注意点があります。
まず、メッセージの再送ロジックには注意が必要です。Cloud Pub/Sub で Message Ordering が有効化されているとき、 あるメッセージが再送されると、同じ ordering key が指定されている後続全てのメッセージが再送されます。 例えば、同じ ordering key が指定されているメッセージ 1, 2, 3
を順に Publish し、そのうちメッセージ2
がnackされて再送された場合、後続のメッセージ3
は例えackされていても再送されます。再送時のアプリケーション側のパフォーマンスについては注意が必要です。
ref: Order messages | Cloud Pub/Sub Documentation | Google Cloud
また、Subscriber Client が複数存在する際の挙動についても留意する必要があります。「Subscriber Client が複数存在する」とは、一つの Subscription に対して(例えばその Subscriber が水平方向にscaleして)Subscriber が複数存在する状態のことを指します。この時、Pub/Sub は ordering key に基づいて、同じ key のメッセージを同じ Subscriber に送信します。なので一般的な sharding を考える時同様、ordering key の粒度を細かくし、hot spot を避けることが大事です。
ref: Cloud PubSubのOrdering Keyで考慮すること - Carpe Diem
Pub/Sub の Message Ordering については公式ドキュメントの他にこちらの記事も非常に参考になるので是非読んで見てください。
Google Cloud Pub/Sub Ordered Delivery | by Kamal Aboul-Hosn | Google Cloud - Community | Medium
エラーハンドリングと Dead-letter topic
Pub/Sub はデフォルトでは無限回メッセージの再送を行います。なので、retryによって成功し得ないエラーが発生した場合、メッセージが再送され続け、Subscriberが受け取るメッセージ量も常に増加し続けます。全てのメッセージを確実に処理する必要があるアプリケーションでは、エラーを解決しない限り再送され続けるべきなので、この設定でも問題はありません。
しかし、一定のエラーを許容できるシステムの場合は、数回のretryで解決しない場合はそのメッセージの処理を諦めたい場合があります。
その時に使えるのが、Dead-letter topic です。Dead-letter topic を設定すると、ある一定の回数送信に失敗した場合にそのメッセージを Dead-letter topic へと移すことができます。
If the Pub/Sub service attempts to deliver a message but the subscriber can't acknowledge it, Pub/Sub can forward the undeliverable message to a dead-letter topic
ref: Handle message failures | Cloud Pub/Sub Documentation | Google Cloud
Dead-letter topic に送信されたメッセージやその数は取得可能なので、後日リトライするためのロジックを実装したり、モニタリングして必要に応じてアラートを発生させたりできます。
まとめ
今回は利用する言語によらないPub/Subの注意点を記載しました。
次はGo言語のPub/Subクライアントライブラリを利用する際に意識することについても書ければと思います。よろしくお願いします。