なぜPub/Subか?
メッセージを非同期でやり取りでき、メッセージ送信側はそのメッセージがどこでどのように使われているか意識することなく配信できるので責務を明確にでき、メッセージ受信側からも送信されてきたものをどう扱うか?に責務を限定できるため双方にとって依存度が低い開発ができるためPub/Subを使うことにしました。
構成イメージ
メッセージフロー
ライフサイクル
- パブリッシャーがメッセージを送信
- メッセージがCloud Pub/Sub内のストレージに書き込まれる
- Cloud Pub/Subがメッセージを受信したことをパブリッシャーにACKして、トピックに属する全てのサブスクリプションに配信することを保証
- メッセージをストレージに書き込むと同時に、サブスクライバーにメッセージを配信
- サブスクライバーは、メッセージを受信したことをCloud Pub/SubにACK
- 少なくとも1つのサブスクライバーがメッセージ受信のACKを送ってきたらCloud Pub/Subはストレージからメッセージを削除
メッセージについて
メッセージ公開ステップ
- データを含むメッセージを作成
- Cloud Pub/Subサーバーにリクエスト送信
- 目的のトピックに公開
使用上の注意点
REST で JSON を使用する場合、
- メッセージ データを base64 でエンコードする
- デコード後のリクエスト全体のサイズ(メッセージを含む)は 10 MB 未満
- メッセージ ペイロードを空にしない
- 空でないデータフィールドか1 つ以上の属性が含まれる
カスタム属性
メッセージにメタデータとして埋め込める。
Key-valueでテキストかバイトで指定。
以下、サンプル
{
“data”: string,
“attributes”: {
string: string,
…
},
公開に失敗した場合
自動的に公開リクエストがリトライされる。
※リトライを妨げるエラーが発生しなし限り
リトライをカスタマイズすることもできる。が、ライブラリによってカスタマイズをサポートしていないケースあり。
トピックについて
トピック操作
- 作成
- 削除
- 一覧取得
(公開操作など)これ以外にもある?要調査。
作成方法
- コンソールから作成
- gcloudコマンドで作成
gcloud pubsub topics create my-topic
3. アプリケーションから作成(Client Library利用)
https://github.com/GoogleCloudPlatform/golang-samples/blob/master/pubsub/pubsub_quickstart/main.go
4. terraformで作成https://www.terraform.io/docs/providers/google/r/pubsub_topic.html
サブスクリプションについて
役割
トピックとサブスクライバーアプリケーションが関連付けられる。
= トピックにメッセージが公開されてもサブスクライバーが受信するためには、トピックに対してサブスクリプションが作成されている必要がある
サブスクリプションが持つプロパティ
配信方法
デフォルトではpull方式で配信される
有効なHTTPS pushエンドポイントURLを指定するとpush配信に切り替えることができる。
Pull方式に戻すには空のURLを指定する
確認応答期限
確認応答を待つ時間。
これを過ぎるとメッセージが再送される。
デフォルトは10秒で、最長600秒。
サブスクリプション自体の有効期限
デフォルトでは、サブスクリプションの非アクティブ状態が31日間続くと期限切れになる。(作り直し?影響範囲は?)
アクティビティ(有効なpull, pushの成功)などを検出するとリセットされる。
サブスクリプション操作
- 作成
- Push先エンドポイント、push/pull方式変更
- 有効期限変更
- 一覧取得
- アクセス(特定トピックのサブスクリプション)
- 削除
公式サンプル
本を登録できるアプリケーション
パブリッシャー側のアプリケーション
- 本を登録できる
- 登録した本の一覧が見れる
- 登録した本を削除できる
- 本が登録した際にPublishする
サブスクライバー側のアプリケーション
- Publishされた本の画像や詳細データを取得してくる
- ↑データでpublishされたデータをupdateしている
- goルーチンでずっとsubscribeしている
どんなpub/subアプリか?
Publisherがpublishしたデータをsubscriberがアップデートするというアプリ。publisherがユーザーに本の情報を入力させ、DBにデータ格納、publishするということを担当し、subscriberが受け取ったIDの本情報を取得、画像URLやタイトルなどのアップデートを行っている。
Subscribeの方式としてはpull型
公式ライブラリ
Go
Clientについて
func NewClient(ctx context.Context, projectID string, opts …option.ClientOption) (c *Client, err error)
上記が用意されており、GCPのプロジェクトIDを指定して実行する
気になった点が、適当なプロジェクトIDを指定してもエラーにならなかったこと。ローカルのマシンが gcloud auth login をしているとか関係あるのかな?と思って revoke してみても変わらなかった。
Topicについて
生成したClientに対して以下のような呼び出しで参照できる
client.Topic(“TopicID”)
こちらも適当なtopicを指定してもエラーにならなかった。
Existsメソッドで確認したところ結果が False で返ってきたのでちょっと一安心。ここまできてやっと確認できるのか。。悩ましい。
用語
トピック
パブリッシャーがメッセージを送信する名前付きエンティティ
サブスクリプション
メッセージストリームを表す名前付きエンティティ。
このストリームは特定の1つのトピックからサブスクライバーアプリケーションに配信される。
メッセージ
パブリッシャーがトピックに送信し、最終的にはサブスクライバーに配信されるデータ。データと属性を組み合わせることもできる。
メッセージ属性
パブリッシャーがメッセージに設定できるkey-valueペア。
パブリッシャー
特定のトピックに関するメッセージを作成してメッセージサービスに送信するアプリケーション
サブスクライバー
特定のサブスクリプションに関するメッセージを受信するアプリケーション
メモ
サブスクリプションのメッセージ受信方法について
- Cloud Pub/Subのサブスクリプションからサブスクライバーが選択したエンドポイントにPush
- サブスクライバーがCloud Pub/Subのサブスクリプションからpull
の2つがある。
pushもpullもできる。
エンドポイントの選択はどこでどのような選択ができるのだろう?
サブスクライバーがメッセージを受信すると
サブスクライバーからCloud Pub/SubのサブスクリプションにACKされ、サブスクリプションのメッセージキューから削除される
パブリッシャー/サブスクライバーの条件
パブリッシャー
googleapis.com に HTTPS リクエストを行えるアプリケーション
サブスクライバー
Pull型:
googleapis.com に HTTPS リクエストを行えるアプリケーション
Push型:
HTTPS を介した POST リクエストを受け入れられる Webhook エンドポイント
メッセージの保持期間
通常、サブスクライバーアプリケーションからACKがあった場合、メッセージはストレージから削除される。
が、確実に配信できなかったメッセージについては最大7日間保持する
サブスクリプションが構築されていないと?
トピックに対してパブリッシュされたイベントは失われる
所感
pull型もpush型もアプリケーションを立ち上げておく必要があることには変わらない。push型の方が受ける側として作りやすいような気がするけどどうなんだろ?push型だとgcpサービスからアクセスがあるという認識であっているか?となるとネットワーク上なんらかを解放する必要がある?
Push型を選ぶとpush先のurlを指定することになるので、そのurlの管理もセットでsubscriberでやる必要ありそう。
Guiからsubscriptionをpush型で作成しようとすると、urlが正しくないとそもそも登録できなかった。検証してみないと分からない。