Google Cloud Pub/Sub 入門


今回はGoogle Cloud Pub/Subについてまとめていきます。

Google Cloud Pub/SubはPublicクラウド型のメッセージングサービスです。巨大なキューのようなものです。

似たような製品にAmazon Kinesis、Apache Kafka、ビッグデータ向きではないですがAmazon SQSなどがあります。

Google Cloud Pub/Sub概要

Google Cloud Pub/Subはメッセージングサービスで、巨大なキューのようなものです。

Topicと呼ばれるメッセージの入れ物を作り、そこに対してメッセージをpublish(投入)します。その後、SubscriptionというTopicのデータの取得状況を管理するものを作り、最後にそのSubscriptionからSubscribe(メッセージ取得)を行います。

この辺りの情報は一度公式ページを読んでみると良いと思います。

[

引用:Google Cloud Pub/Subとは https://cloud.google.com/pubsub/docs/overview

Pub/Subはat-least-onceで、全てのメッセージは最低でも1回配送されます。つまりたまに重複します。メッセージの取得側は重複することを見越してべき等な処理を実現する必要があります。

メッセージの保管は7日間です。(Kinesisは1日、有料で最長7日に延長可能)

クイックスタート

クイックスタート: gcloud コマンドライン ツールの使用

Console を使用したクイックスタート

上記に従ってgcloudコマンドやTopicを用意してPub/Subを使うことができます。詳細は公式ページを参考にしてやってみると良いと思います。

Javaコードの部分は詳しくは後述します。

 

ここから先は公式ドキュメントでは分かりづらいと思った点について書いていきます。全部は網羅しませんので、公式ドキュメントも読んだ方が良いです。

料金体系

料金

1 か月あたりのデータ容量GB あたりの料金
最初の 10 GB$0.00
次の 50 TB$0.06
次の 100 TB$0.05
150 TB 超$0.04

データ容量は、pull、push、パブリッシュの各オペレーションのメッセージ データと属性データのみを使用して計算されます。計算に含まれるのは、1 リクエストあたり(1 メッセージあたりではなく)1 KB 以上のデータです。

引用:料金 https://cloud.google.com/pubsub/pricing?hl=ja

最後の一文は意図がよくわかりませんが、ようするにデータを入れる時も取る時も課金されるようですね。Kinesisは(PUTペイロードユニットは無視するとして)Shard単位での課金なので、このあたりはだいぶ違いますね。

Kinesisと比較した場合のPub/Subの料金 (Kinesisの最大22倍)

Kinesisは1shardで1MB/sec publishできる性能があります。毎秒常に1MBのデータをpublishし、毎秒常に1MBのデータをsubscribeするケースで料金比較を行ってみます。

KinesisはTokyo region 1shard $0.0195/hourなので30dayで$14.04

Pub/Subは1GB $0.06だとして、1MB/secを30dayにすると2,592,000MB。2592GB。これは片道だけで、もう片道(受信時)も考慮して2倍で5184GB。つまり$311.04

KinesisとPub/Subは22倍の価格差があるのは非常に大きいですね。とはいえ、上記はKinesisの1shard 1MB/secという上限ギリギリでの試算です。実際にKinesisを使うときはもっとshardに余裕を持たせると思います(Shardを多めに作成します)。それに対してPub/Subは転送データでの従量課金なので、実際には22倍ではなく10倍とかその程度だと思います。

かなり価格差はありますが、Kinesisで言うSplit shardなどの運用もありませんし、Pub/Subはデフォルトでマルチリージョン対応しているなど、機能面ではPub/Subが大幅に勝っている印象です。単純にKinesisの22倍高い(悪い)とは言えないので、そこはご了承ください。

Pub/SubはTopicを作成する時にRegionを選ぶというようなことはしません。データは複数のRegionでコピーされているようです。また、Pub/Subへ接続した時にクライアントとデータセンターが最も近いものが自動で選ばれるようです。KinesisはRegion固定なので、このあたりはだいぶ違いますね。詳しくは以下をご覧ください。

https://cloud.google.com/pubsub/architecture?hl=ja

Subscription

Topicは背後にMessage Storageというメッセージの入れ物を持っているのでいわゆるストレージ・フォルダのようなものだと考えることができます。Subscriptionはこの手のメッセージングサービス独特のものなので少し解説します。

通常、Pub/Subの利用者は一度取得(処理)したメッセージは再度取得したいとは思わないはずです。そのため、このメッセージは既に処理した、というマーキング的な情報を管理しているのがSubscirptionです。

Pub/Subの利用者が複数のアプリケーション(例えばTopicに入れたデータを常時RDBMSへINSERTするアプリと、Diskへ書き込むアプリ)を持っているケースもあります。そのとき、複数のSubscriptionを作成して、各々にメッセージを取得させることもできます。(Subscriptionを複数作れる)

Subscriber

SubscriberはSubscriptionからメッセージを取得する者です。例えばPubSub SDKを使う場合、そのSDKを使ってメッセージを取得するアプリ(Subscriber objectでAPI操作)がSubscriberです。

上記の画像の場合、Subscriberは1つですが、Subscriberは同一のSubscriptionに対して複数作成でき、これによって負荷分散・Scale outが可能です。

Subscriptionでデータ取得完了したとマークするack

各メッセージングサービスのSubscriberはどこまでメッセージを取得したかを表す情報をcheckpointとして、Kinesisの場合DynamoDBへ、Kafkaの場合Zookeeperへ記録します。

Pub/Subの場合はSubscirptionに記録されます(内部的にどのような値・データ構造になっているかは不明)。記録する方法はcheckpointとして位置を記録する方式ではなく、「このメッセージは処理済み」としてマークする方式です。マークは取得したメッセージに対してackを返答する形式です。つまり単一のメッセージに対してackされたかどうかの状態をSubscriptionは持っているようです。

ちなみにPubSub SDKを使う場合 consumer.ack() のような感じでメッセージを処理し終わった後でackします。これによって、そのメッセージが再送されてくることはありません。

ackを返さないといけないメッセージの確認応答期限

メッセージの確認応答期限

Subscriptionを作成するときに確認応答期限というものを決められます。(デフォルト10秒)

Subscriberはメッセージを取得した後、その期限内にackを返さなくてはいけません。それができない場合、そのメッセージは正しく取得されなかったと見なされ、再送されます。

再送のタイミング

期限はデフォルトの10秒だとして、ackを全く返さない場合、常に10秒ごとにそのメッセージが再送されてくるのかというとそうではないようです。

どうやらExponential backoffの仕組みによって再送間隔をずらしているようです。

再試行ポリシー

プル

受信が確認されなかったメッセージは、確認応答期限に達すると、配信から最長 7 日間は再度プルできるようになります。

プッシュ

プッシュ エンドポイントからエラーコードが戻ると、メッセージは指数バックオフ ポリシーで最長 7 日間再試行されます。

引用:サブスクライバー ガイド https://cloud.google.com/pubsub/subscriber?hl=ja#push_pull

(自分が検証したのはプル方式のSubscriberですが、)ドキュメントにある通り指数バックオフ(Exponential backoff)のようです。

ackの代わりにnackを返して、即時再送

上記でconsumer.ack()と言っていますが、nack()というAPIも存在します。nackは否定応答という意味です。

nackを返した場合、そのメッセージは確認応答期限を待たずに即時再送されるようになります。

メッセージの順序

メッセージの順序指定

KinesisやKafkaにはメッセージの順序保証がありますが、Pub/Subにはありません。とは言ってもKinesisもKafkaも1つのshard, partition内での順序保証なので、shard, partitionへのメッセージの投入および取得を考えて使わないと完全な順序にはなりません。

KinesisとKafkaは読み出し位置の管理がcheckpoint方式なのに対して、PubSubはメッセージごとのack方式というのもこのあたりに関係しているようですね。ちなみにAmazon SQSはどちらかというとack方式です。

非公式ドキュメント

公式以外にもいろいろな方が資料を公開されているのでそれについてまとめます。

スケーラブル GCP アーキテクチャ - DeNA

DeNAでPub/Subを使っている話です。App EngineとPub/Subを組み合わせている部分に重点が置かれています

GCPを利用したデータ分析プラットフォームについて - CA Reward, Inc.

詳しくは書かれていませんが、Pub/Subとfluentdを使っているようです

Google Cloud Platform、15のサービスで永久無料枠を提供開始 - @IT

Pub/Sub 毎月初めの10GBが無料枠になったのは2017年3月頃からだったんですね

Apache Kafka & Google Cloud Pub/Sub 主要機能の比較 - サイバーエージェント

Pub/Subは高いので、ある程度の規模である場合、オンプレのKafkaの方がトータルで見てコストが低いと思います。そういう判断の材料になりそうですね

ゲスト投稿 : MQTT と Cloud Pub/Sub で IoT アプリケーションを構築 - Google Cloud Platform Japan Blog

(MQTT, RabbitMQは詳しくありませんが、)IoTにおいてHTTPヘッダが転送量的な面で問題になるというのはなるほどと思いました

Cloud Storage のオブジェクト イベントが Cloud Pub/Sub サブスクリプションの対象に - Google Cloud Platform Japan Blog

今回は調査していませんでしたが、AWSのS3イベント => Lambdaと同じような感じで、GCSイベント => Pub/Sub topicへPut ということが可能なようです。GCSイベント => CloudFunctionsも可能です

まとめ

駆け足になってしまいましたが、Pub/Subについて重要だと思った点をピックアップしました。

次はSDKを利用して実際にPub/Subを操作していきます。

次回:Google Cloud Pub/Sub Java Client Library 入門 (サンプルはScala)