Pub/Subのスキーマとは
Google CloudのメッセージングサービスPub/Subは、オプションでトピックにスキーマを適用することができます。スキーマを適用した場合、スキーマに準拠しないメッセージの公開を制限します。また、スキーマは変更があるとリビジョンをとることができ、複数のリビジョンを同時にトピックに関連付ける事ができます。一方で、スキーマで定義されたフィールド以外のデータ入っていても公開できたりするので、実際の様子を見てみたいと思います。
スキーマの作成
コンソールからスキーマは作成できます。スキーマの定義は、Apache AVROかプロトコルバッファーでできます。ここでは、person
というスキーマを作成し、フィールドにName
とAge
を持ちます。
そして、トピックにスキーマを適用できます。トピックの作成や編集時に、スキーマを使用する
を選択し、対象のスキーマを選びます。
以上です。簡単ですね。
メッセージを公開してみる
まずは、スキーマ通りのメッセージを投げ込んでみます。コンソールでもできますが、コマンドで実行します。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Taro", "Age": 3}'
messageIds:
- '11327282810297513'
特にエラーなく、メッセージIDが返ってきました。次にサブスクリプションから取得してみます。
$ gcloud pubsub subscriptions pull projects/$(gcloud config get-value project)/subscriptions/schema-changing-test-sub --format="value(message.data)" --auto-ack | jq
{
"Name": "Taro",
"Age": 3
}
取れました。ま、これは当たり前ですね。
スキーマに定義されているフィールドを含めて公開してみる
次にAge
を含まないメッセージをトピックに投げ込んでみます。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Jiro"}'
ERROR: (gcloud.pubsub.topics.publish) INVALID_ARGUMENT: Invalid data in message: Message failed schema validation.
- '@type': type.googleapis.com/google.rpc.ErrorInfo
domain: pubsub.googleapis.com
metadata:
message: Message failed schema validation
revisionInfo: 'Could not validate message with any schema revision for schema:
projects/111111111/schemas/person, last checked revision: revision_id=df0473fb
failed with status: Invalid data in message: Field was not found in JSON object:
Age.'
reason: INVALID_JSON_AVRO_MESSAGE
Jiroは怒られました。Age
がないよと。ちゃんとチェックしてくれていますね。
スキーマにないフィールドを一部含めずにメッセージを公開してみる
では、スキーマにないフィールドが投げ込まれたときもちゃんと拒否されるでしょうか。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Sabro", "Age": 21, "Gender": "Male"}'
messageIds:
- '11327344946086872'
普通に通っちゃいました。そして下記の通りサブスクライバーからも見えます。
$ gcloud pubsub subscriptions pull projects/$(gcloud config get-value project)/subscriptions/schema-changing-test-sub --format="value(message.data)" --auto-ack | jq
{
"Name": "Sabro",
"Age": 21,
"Gender": "Male"
}
つまり、余計なものは許可されます。
スキーマを変更してみる(初期フィールドの削除)
フィールドの削除をコンソールから行います。スキーマを開いてリビジョンの作成
とすると下記のように編集できます。
ところが、確定
しようとしたら怒られました。オプションじゃないフィールドは消せないと。
スキーマを変更してみる(フィールドの追加)
であれば、追加してみます。
が、また怒られました。これもオプションじゃないフィールドだからとのこと。
オプションフィールドとするにはdefault
を設定すれば良さそうです。
そしてこれは無事成功しました。するとこんな感じでリビジョンができます。
スキーマに追加したフィールドを含めずにメッセージを公開してみる
まずは、新しいスキーマのみをトピックに適用します。次のように、トピックの編集でリビジョンの範囲を最新のリビジョンのみになるようにします。
反映にはすこし時間がかかるようなので数分待ってから、まずは普通にスキーマにあるフィールドを全部含めたメッセージを公開します。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Shiro", "Age": 23, "Gender": "
Male"}'
messageIds:
- '11327883030332909'
$ gcloud pubsub subscriptions pull projects/$(gcloud config get-value project)/subscriptions/schema-changing-test-sub --format="value(message.data)" --auto-ack | jq
{
"Name": "Shiro",
"Age": 23,
"Gender": "Male"
}
これはいけます。では、Gender
を削ってみます。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Shiro", "Age": 23}'
ERROR: (gcloud.pubsub.topics.publish) INVALID_ARGUMENT: Invalid data in message: Message failed schema validation.
- '@type': type.googleapis.com/google.rpc.ErrorInfo
domain: pubsub.googleapis.com
metadata:
message: Message failed schema validation
revisionInfo: 'Could not validate message with any schema revision for schema:
projects/111111111111/schemas/person, last checked revision: revision_id=e9712880
failed with status: Invalid data in message: Field was not found in JSON object:
Gender.'
reason: INVALID_JSON_AVRO_MESSAGE
はじかれました。
初期作成時にAgeにdefaultつけてみる
では、はじめに作る際にdefaultつけるとどうでしょうか。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Goro"}'
ERROR: (gcloud.pubsub.topics.publish) INVALID_ARGUMENT: Invalid data in message: Message failed schema validation.
- '@type': type.googleapis.com/google.rpc.ErrorInfo
domain: pubsub.googleapis.com
metadata:
message: Message failed schema validation
revisionInfo: 'Could not validate message with any schema revision for schema:
projects/111111111111/schemas/person, last checked revision: revision_id=23f1cb3a
failed with status: Invalid data in message: Field was not found in JSON object:
Age.'
reason: INVALID_JSON_AVRO_MESSAGE
ま、ここは同じく弾かれますね。ただ、Age
を消すことはできました。
そして、Name
だけで公開できました。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Goro"}'
messageIds:
- '11327997684512795'
複数のリビジョンを適用してみる
では、最後にこれまで単一のリビジョンをトピックに当ててきましたが、複数のリビジョンを当てるとどうなるか見てみます。スキーマの変更が発生して移行期間などこういう状態が考えられます。
まずトピックの編集でリビジョンの範囲の指定で異なるリビジョンを指定します。
これでどちらのスキーマのメッセージも通るはずです。つまり、先程までGender
がないと怒られましたが、許してくれるようになるはずです。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Tokuro", "Age": 42}'
messageIds:
- '11327156735462791'
いけましたね。
記録のため、他に色々試しておきます。
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Tokuro"}'
ERROR: (gcloud.pubsub.topics.publish) INVALID_ARGUMENT: Invalid data in message: Message failed schema validation.
- '@type': type.googleapis.com/google.rpc.ErrorInfo
domain: pubsub.googleapis.com
metadata:
message: Message failed schema validation
revisionInfo: 'Could not validate message with any schema revision for schema:
projects/111111111111/schemas/person, last checked revision: revision_id=2443500c
failed with status: Invalid data in message: Field was not found in JSON object:
Age.'
reason: INVALID_JSON_AVRO_MESSAGE
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Tokuro", "Age": 42, "Gender": "Female"}'
messageIds:
- '11328254979892295'
$ gcloud pubsub topics publish schema-changing-test --message='{"Name": "Tokuro", "Age": 42, "Gender": "Female", "BloodType": "A"}'
messageIds:
- '11328291513640241'
まとめ
- スキーマで定義されたフィールドがメッセージにないと公開できない
- スキーマに無いフィールドが入っていても公開できるし、サブスクライバーもそれを受け取れる
- スキーマ作成時に
default
をつけたフィールドはあとから削除できる - 逆に、defaultのない初期フィールドはあとから削除できない
- defaultをつけないとあとからフィールドを追加できない
- リビジョンの範囲を指定して、複数リビジョンを適用することで、複数のスキーマに準拠したメッセージを同時に許可できる