やってみた: Spanner Change stream と Dataflow で別プロジェクトの BigQuery にデータを流す

pre-amble

「Spanner のデータを Change stream, Dataflow を使って別プロジェクトにある BigQuery にデータを流してみよう」というお題をもらったのでやってみた。BigQuery 以外触ったことなかったのでまずそれぞれどんなもんだい、ってとこから始まった。

setup

  • project A: Spanner, DataFlow
  • project B: BigQuery

Spanner (Change stream) → Dataflow → BigQuery

Spanner

Spanner とは

何も知らないので、Cloud SQLRDBMS なのに対して Spanner は KV store なのかな? とか思ったけど、そんなことはなく RDBMS みたいに使えて*、PostgreSQLGoogle Cloud SQL の2つの SQL dialect の選択肢がある。

*公式が「Spanner provides a solid foundation for all kinds of applications with its combination of familiar relational database management system (RDBMS) features, such as ... and unique features such as strong external consistency via TrueTime and high availability via native synchronous ...」と言ってるので、 RDBMS と言い切るのも微妙な気がした。RDBMS +α って感じ?

この SO だと、「Cloud SQL で事足りるならそれで OK、それ以上のデータ量とかの要件があるなら Spanner」って言ってた↓

sample DB + backend

「Spanner はコストがえぐいから、とりあえず free instance を使うといいよ」とのことだったので見てみたところ、90日間使える free instance があった。個人的に、90日を過ぎて消し忘れても 30-day grace period の後に勝手に消してくれるのが嬉しいポイント。

Spanner free trial instances overview  |  Google Cloud

で、さらにすごいのがチュートリアルで勝手にデータを流してくれるバックエンド + DB がコマンド2つで用意できるところ... というのがこの辺に書いてある↓

Create a Spanner free trial instance and sample application  |  Google Cloud

30分もあれば上のページにある内容はとりあえず動かすところまではいける (理解はともかく)。

自分用コマンド↓

# in tab 1
gcloud auth application-default login
    
gcloud spanner samples backend \
    finance --instance-id \
        <instance-id>
        
# in tab 2
gcloud auth application-default login

gcloud spanner samples workload \
    finance

outputs

というわけで、

  • trial-instance という Spanner instance
  • の中に、 finance-db というデータベース
  • の中に、 Accounts, TransactionHistory などのテーブル

が作成された状態がここまで

Change stream

Change stream とは

個人的に、

CREATE CHANGE STREAM SingerAlbumStream
FOR Singers, Albums;

という DDL で作成するものですよというのが一番わかりやすい説明かも。

公式の説明だと、

A change stream watches and streams out a Spanner database's data changes—inserts, updates, and deletes—in near real-time.

...

Spanner treats change streams as schema objects, much like tables and indexes. As such, you create, modify, and delete change streams using DDL statements, and you can view a database's change streams just like other DDL-managed schema objects.

とのことで、

  • データベースへの変更を stream するモノ
  • モノ = schema object → table, index と同じように扱える

というのが自分的ポイントだった。

sauce: Change streams overview  |  Spanner  |  Google Cloud

Change stream の作成

Change stream はデータベース全体に対して作成することもできるし、特定のテーブル・カラムに対して作成することもできる。今回は TransactionHistory に対してだけ作ってみたかったので (なんとなく)、↓の DDL を Spanner Studio* の中で実行した。

CREATE CHANGE STREAM TransactionStream
FOR TransactionHistory

(CamelCase なのはサンプルコードに従ったから)

*Spanner Studio は Spanner に対していろいろクエリが書けるエディタで、BigQuery に慣れてれば違和感なく使えると思う。多分。

outputs

trial-instance の中に finance-db.TransactionHistory に対する change stream ができた

Dataflow の作成

作業的にはここまでと同様ボタンぽちぽちで終わるんだけど、Dataflow job の設定にあたっていろいろわからないことがあったので一番大変だった。↓の記事がめちゃ参考になった。

【Cloud Spanner】Change StreamsをBigQueryに保存して利用する

概要としては、

  • Spanner change stream → BigQuery の Dataflow job を作成するには、すでにある「テンプレート」ってやつを使えばすぐできる (テンプレートを選択して Run Job をクリックするだけ)

BigQuery dataset (in other project) の作成

Dataflow job を作成してるときに destination を作ってないことに気がついたので、お題の「別プロジェクトの BigQuery」を設定した。

↓ の画像のようなフィールドなんだけど、(1) dataset 単位で job を作る (2) datasetId だけでなく project.datasetId の形式で設定できるというのがポイントだった。

(1) に関しては、change stream の最大の単位が DB なので (インスタンスではなく) よく考えたら「たしかに」ってなった。 (2) に関しては、前回の Datastream みたいに UI で裏技を使わないと別プロジェクトの BigQuery を指定できない、とかではないので安心した。

Service Agent への権限付与

ベスプラ的には service account を別途つくるべきなのだが、いったん何も指定しないで job を作成することにした。で、このときどの service agent が使われるかなんだけど、結論 Compute Engine と同じ <project number>-compute@developer.gserviceaccount.com になるっぽい (何も指定しなかったらこれになった)。

ただ、 xx-compute@... とは別に Dataflow の service agent はあるようなので、本来は Dataflow の方が使われるのか..? ほんとは作ったあとに権限をつけたので、ここらへんはちゃんと確認できてえいない。

Service agents  |  IAM Documentation  |  Google Cloud

何はともあれ principal がわかったので、別プロジェクトにいって <project number>-compute@developer.gserviceaccount.com に権限をつけにいった。Dataflow Service Agent の権限を見ると、bigquery.capacityCommitments.* など BigQuery Data Editor にない権限もついているので今回は BigQuery Admin をつけた。Data Editor にない権限が今回の job において使われるのかは未確認なので、ほんとは Data Editor でもよかったのかも? BigQuery Admin には bigquery.jobs.* がすでについているので、 BigQuery Job User はつけなかった。

「まじか」ってなったところ

(1) Dataflow job には pause/resume がない

ストリームなのでそれはそう案件なのかもだけど、 Dataflow job は一度止めると「再開」というのがない。代わりに、止めたジョブをクローンすることで再開的な挙動にさせることができるけど、停止〜再開してた間のデータがどうなるのかはよくわかってない

(2) 同じ名前の実行中の Dataflow job は複数作成できない

1 のところで、止めたあとに job をクローンしようとしたんだけど、名前をそのままにしておいたらエラーになった。ただ、job は止まるのに時間がちょっとかかる (体感10分くらい?) ので、止まるまで待てば同じ名前の job は作成できる。

outputs

  • Dataflow job
  • IAM binding for Compute Engine default service account x BIgQuery Admin in the other project

これで Spanner → Change stream → Dataflow job → Bigquery ができて、 BigQuery にデータ入ったことも確認できた。

調べもの

Dataflow job > "metadata instance ID" "metadata database" とは??

いかんせん Dataflow のジョブは設定項目があって、必須項目の中だけでも結構 ??? になった

Create and manage change streams  |  Spanner  |  Google Cloud

ここに書いてあって、 change stream の internal state を管理するためのデータを metadata instance/database が必要。これは実際のデータが入ってる instance/database と同じでもいいけど、↓の理由から分けることがおおすすめ

  • 実データの方を readonly アクセスにできる
  • DB 全体を watch する change stream (FOR ALL) の場合、change stream のメタデータへの変更か実データへの変更かを気にしなくていい

Change stream: exclude TTL based deletes

Spanner のデータには "TTL" (time-to-live) を設定できて、GCS の lifecycle policy のように一定期間後自動的にデータが削除されるようにできる。で、 Change stream でこの TTL 起因の delete を watch しないように設定できる。