2021 年の Cloud Spanner を振り返る

Cloud Spanner 冬休み講座

Takahiko Sato
google-cloud-jp

--

この記事は Google Cloud Japan Advent Calendar 2021 の 14 日目の記事です。本記事は 2021 年 12 月 14 日現在の情報に基づいて書いています。

こんにちは、Google Cloud で Database Specialist をやっている佐藤です。今回は Cloud Spanner 冬休み講座と題して、2021 年の Cloud Spanner を振り返ってみようと思います。これらをおさえておけば、来年に向けた Cloud Spanner の復習と予習はバッチリ!さて 2021 年は Cloud Spanner にとってどんな年だったでしょうか?

目次

1 時間目:Cloud Spanner はどんなデータベース?

今回このブログにたどり着いた方の中には、Cloud Spanner について初めて触れるという方もいらっしゃると思います。最初に Google Cloud のマネージド データベース(RDBMS)サービスである Cloud Spanner とはどんなサービスなのか 3 行(+ 図)で振り返りたいと思います。

  • 例えリージョン障害が起こっても DB インスタンスが止まらない!非常に高い可用性を誇る RDBMS
  • 必要なノード数を指定するだけで、後はそれに合わせて全自動シャーディング!読み込みだけじゃなく、書き込みもスケールアウト可能な RDBMS
  • 上記の実現に運用負担はほぼ無し!運用がとても簡単な RDBMS

図 1. は Cloud Spanner を実際に構築する際のコンソールの画面です。構築は本当に簡単で、「どこのリージョンにどの構成で立てるか」、「何ノード立てるか」、これらを入力して「作成」ボタンをクリックするだけです。簡単でしょう?

図 1. Cloud Spanner インスタンスの構築画面

今回のアドベントカレンダー 11 日目の記事「データベースエンジニアから見たCloud Spanner」にて、上記特徴の裏側についてまとめられていますので、そちらも併せて読んでもらえればと思います。

2 時間目:インスタンスの運用管理機能の向上

0.1 ノード インスタンス登場

さて最初のテーマは、インスタンスのノード管理についてです。Cloud Spanner にて、1 ノードより小さいインスタンス サイズを提供したことです。

これまで Cloud Spanner をスモールスタート(最小コスト構成)しようとしても、どうしても 1 ノード インスタンスからのスタートでした。例え 1 ノードでも裏は 3 多重で冗長構成になっている Cloud Spanner は、とても高い可用性を実現できます。一方で可用性及び処理性能が不要な場合、特に開発環境の場合、例え 1 ノードだけの起動であってもコストが気になっていたのは事実です。

Cloud Spanner の料金体系は、以下の 4 つの要素で構成されます。

  • ノード数(インスタンスのコンピューティング容量)
  • データサイズ(実データ)
  • データサイズ(バックアップデータ)
  • 外向きネットワーク転送量

ノード以外の要素は、実際に使わない限り発生しません。一方でノード課金については起動しているだけで発生するため、より低コストなインスタンス提供などが求められてきました。

こうして登場したのが、より細かいインスタンス サイズ(Granular Instance Sizing)の提供です。これにより 1 ノードより小さくてコストの低いインスタンスを使うことができるようになりました。

具体的には、1 ノードの処理性能を 1,000 処理ユニット(Processing Units)と定義して、100 処理ユニット単位でインスタンスを作れるようになりました。0.1 ノードみたいなものですね。最小 100 処理ユニットからスタートし、100, 200, 300, ..., 900, 1000(1ノード) という形で 9 パターンのサイズを作れます。なお 1 ノード以上については、これまで通り 1 ノード単位での追加になります。例えば 1,500 処理ユニット(1.5 ノード)のインスタンスというものは作れません。

図 2. 100 処理ユニットから指定可能に(1 ノード = 1000 処理ユニット)

2021 年 12 月 14 日現在、1 ノード未満の Cloud Spanner インスタンスはプレビュー版としての提供になっていて、SLA の対象とはなりません。主に開発環境など可用性を求めない環境で試される方が多いと思いますので、あまりに問題になることはないとは思いますが、その点ご注意いただければと思います。SLA の対象となる必要がある場合は、一般提供(GA)までお待ち頂ければと思います。

任意の時点のデータを復元する PITR

Cloud Spanner はフルマネージドな RDBMS です。レプリケーション周りの処理も、ノード追加削除時のシャーディングも全自動です。正直必要な運用といえば、性能が足りなくなってきたらノードを追加する、これくらいです。おや、ちょっと待って下さい、データベースの運用で重要なことを忘れていました。バックアップの取得です。図 3. にあるように、ノード追加削除とバックアップの取得は、全自動で動作する Cloud Spanner における数少ない運用項目です。

図 3. シンプルな Cloud Spanner のコンソール

このバックアップ機能に、任意の時点のバックアップを取って復元する機能、ポイントインタイム リカバリ(Point-in-Time Recovery、以降 PITR と記載) が追加されました。

メモ: バックアップ/復元とエクスポート/インポートの違い
Cloud Spanner のバックアップは、復元時に速やかに DB を利用可能状態に持っていくことを目的としており Cloud Spanner のストレージを、専用の形式で保存しています。バックアップ データはインスタンスに紐づき、取得元のインスタンスと異なるリージョン構成のインスタンスに復元することはできません。同じリージョン構成であれば、同一インスタンスの異なる DB として復元したり、異なるインスタンスの DB として復元することも可能です。
Cloud Spanner のエクスポートは、Cloud Spanner のインスタンスの外の世界にデータを取り出すことを目的としており、取り出す(読み取る)ためのジョブとして Dataflow を利用し、格納先として Cloud Storage を利用します。データは汎用的に使える Apache Avro 形式であるため、そのまま BigQuery にインポートしたり、Avro から他のフォーマットに変換して、様々なデータ処理基盤で利用することが可能です。

もちろんこれまでも Cloud Spanner にてバックアップの取得はできました。バックアップ ジョブを実行した時間で取得されるため、そのタイミングを制御することは困難でした。PITR に対応したことで、日時バックアップを正確に特定の瞬間に取得することや、KPI などの分析用にある瞬間の静止断面がほしいといった要望を実現することが、より簡単にできるようになりました。

PITR 機能は、より細かい 2 つの新機能から構成されています。

  1. バックアップ 及びエクスポート画面で、過去にさかのぼって、バックアップを取る過去の時間断面を指定できるようになった
  2. 過去のデータに対してクエリが可能な「ステイル読み取り(Stale Read)」が、これまで最大 1 時間過去までだったものが、最大 7 日過去までさかのぼってクエリが可能になった

バックアップ画面及びエクスポート画面を見てみると、新たにタイムスタンプを指定する項目が増えています。ここに過去のタイムスタンプを指定すると、入力した時刻の断面でバックアップまたはエクスポートが可能です。Earliest version time というところに時刻が表示されていますが、バックアップ取得対象としてさかのぼることができる、最も古いタイムスタンプです。この時刻はどこから来るのでしょうか?

図 4. バックアップとエクスポートで取得する過去の時刻断面を入力できるようになった

どこまで過去にさかのぼれるか、それはデータベースごとに設定されている「バージョンの保存期間(Version retention period)」で決まります。この値は、デフォルトでは 1 時間ですが、最大 7 日まで設定することができるようになったことで、バックアップやエクスポートの幅が広がりました。

図 5. バージョンの保持期間の変更画面

それだけではありません、単純に現在のテーブルの過去のデータにアクセスしたいときは、バージョンの保存期間の範囲であれば、ステイル読み取りにて過去のテーブルに自由にアクセスできるということになります。例えば、BigQuery だとタイムトラベルと呼ばれている機能になりますね。代表的な商用データベースである Oracle Database では、Flashback Query と呼ばれる機能がありますね。

この機能を用いることで、わざわざバックアップから復元などしなくても、特定のテーブルの情報だけ復元するなどといったことも、容易に実現できるようになりました。

バックグラウンド処理のオフロードによる性能向上

Cloud Spanner リリースノートを見ていると、今年 8 月にひっそりと追加された項目がありました。以下の項目です。特にドキュメントへのリンクもありませんね。

August 20, 2021
Cloud Spanner now creates dedicated backup jobs to take backups instead of using an instance’s server resources. As a result, backup time is reduced and backup operations do not affect instance performance.
https://cloud.google.com/spanner/docs/release-notes#August_20_2021

これを読むと、バックアップ取得に Cloud Spanner の処理リソースを使わなくなったと書かれています。どういうことでしょうか?

以前からバックアップを取得されてたユーザーの方は、バックアップ取得時に Cloud Spanner の CPU 使用率のうち、システム部分が大きく上がる様子を目撃していたかと思います。そして 8月の中旬以降、これが見えなくなっていると思います。

これ何が起こったかというと、リリースノートにある通り、Cloud Spanner のバックアップ処理にお客様のインスタンスの CPU リソースを使わなくなりました。つまりバックアップにかかる処理コストがなくなったことになります。結果としてバックアップ負荷が業務影響を与えることはなくなり、またバックアップ取得時間も短縮しました。

このように Cloud Spanner はバックグラウンド処理周りにも改善を入れていて、ユーザーがより快適に使えるようにしていっています。

3 時間目:アプリとの接続方式の拡充

2021 年は、アプリケーションから Cloud Spanner へ接続する方法がたくさん増えた年でもありました。現在代表的な接続方式を列挙すると、以下のような感じでしょうか。

  • Cloud Spanner クライアント ライブラリを用いた接続
  • JDBC ドライバを用いた接続
  • Active Record, Django ORM, SQLAlchemy 各種 ORM 等による接続
  • PostgreSQL インターフェースの提供

この中でも今年大きく拡充された部分として、「Active Record, Django ORM, SQLAlchemy 各種 ORM 等による接続」と「PostgreSQL インターフェース」の提供があります。

[復習] Cloud Spanner クライアント ライブラリを用いた接続

まずはアプリから Cloud Spanner に接続するには、一般にどうするかおさらいをしてみましょう。Cloud Spanner は RDBMS ですので、アプリから接続して、SQL を用いてデータを読み書きすることができます。

アプリケーションは Cloud Spanner API のエンドポイントGoogle Front End と呼ばれる入り口)に接続し、接続先 Cloud Spanner データベースの プロジェクト名/インスタンス名/データベース名 を認証情報と共に渡すことで、後は自動的に目的のデータベースへとルーティングされます。なおこれのすごいところが、Cloud Spanner が何ノードあろうと、日本の東京大阪はもちろん、世界中のどこのリージョンの Cloud Spanner を使おうとも、それを意識する必要はありません。共通のエンドポイントに接続するだけです。

Cloud Spanner に接続するアプリを初めて試す際は、ドキュメントのチュートリアルに、各種プログラミング言語ごとのものがまとまっています。またすべてのコードサンプルがまとまったページもありますので、実際にアプリを開発する際はこちらが役立つと思われます。言語ごとのクライアント ライブラリ自体のドキュメントについては、Cloud Spanner client libraries ページよりたどることができます。

[復習] JDBC ドライバを用いた接続

Cloud Spanner は JDBC ドライバを提供しており、JDBC 対応済みのアプリケーションであれば、容易に Cloud Spanner に接続が可能になります。

Cloud Spanner の JDBC ドライバに関するドキュメントをみると 2 種類の JDBC ドライバを提供していますが、基本的にオープンソース JDBC ドライバと呼ばれる方を利用してください。こちらは Cloud Spanner の Java 用クライアント ライブラリをラップして作られており、Cloud Spanner の新機能にも随時追従しております。

利用方法は、上記ドキュメントまたは GitHub リポジトリにかかれている通り、Maven にて pom.xml に google-cloud-spanner-jdbc を dependency として追加するだけです。

Active Record, Django ORM, SQLAlchemy 各種 ORM 等による接続

さて復習も終わり、ここからが今年の新しいお話です。

データベースを使ったアプリを開発する際、様々なフレームワークを用いて開発されている方もいるでしょう。特に直接 SQL を書いたりすることなく ORM などを用いて、MySQL や PostgreSQL などのデータベースにアクセスしている人もいると思います。そんな開発者の声に答えるため、Cloud Spanner は今年、各種言語の主要な ORM への対応を進めてきました

そしてちょうど先日、Active RecordSQLAlchemy への対応も完了し、主要な ORM への対応が概ねそろいました。アドベントカレンダーの担当日前にリリースされてよかったー!Publickey さんにも取り上げられているのでリンクを貼っておきたいと思います。

現在の主な対応状況をまとめると以下のような形になります。

また上記以外に、Cloud Spanner のユーザーコミュニティで開発されているものもあります。PHP の Laravel 対応のものとして、コロプラさんが OSS として公開している laravel-spanner があります。また、ORM とは異なるものですがメルペイさんが公開した、Go 言語用のコードジェネレーター xo をベースとした yo などがあります。

  • laravel-spanner (Laravel) — PHP [Blog][GitHub] by コロプラさん
  • yo (xo) — Go [Blog][GitHub] by メルペイさん

PostgreSQL インターフェースの提供

Cloud Spanner は RDBMS であり、SQL が利用可能です。しかし RDBMS ごとに SQL って少しずつ方言があったりしますよね?例えば MySQL で使える SQL と PostgreSQL で使える SQL も少しずつ違ったりします。Cloud Spanner で使える SQL は Google Standard SQL と呼ばれるものです。余談ですが Google Standard SQL は BigQuery で使える SQL でも採用されているもので、互換性があります。

Google Standard SQL は ANSI 2011 相当であるため、その範囲においては、RDBMS 問わずある程度 SQL の互換性はあります。しかし例えば CREATE TABLE でのデータ型の指定など、どうしても細かい部分で非互換が出てきてしまいます。

PostgreSQL をお使いの皆様に Cloud Spanner をより簡単に使っていただくため、Cloud Spanner では PostgreSQL インターフェースの提供を開始しました。

2021 年 12 月 14 日現在、プレビュー版をお試しいただくユーザーの募集を行っています。上記ブログにプレビュー募集フォームへのリンクがありますので、興味のある方は応募してみてください。ドキュメントはすでに公開されていますので、併せて読んでいただければと思います。

4 時間目:オブザーバビリティの向上

Cloud Spanner は全自動で動くデータベースです。車で例えるとオートマ車のようなもので、アクセルを踏めばスピードが上がりますので、必要な指標はスピードメーターがあれば十分でした。

一方、全自動であるがゆえに内部状態がわからなかったため、アクセルを踏んでもスピードが上がらなかったとき、つまり想定通りの性能が出なかったとき、それが何故なのか調べるのにサポートに問い合わせるしかなかったという部分も事実です。

2021 年は、Cloud Spanner にとってオブザーバビリティ(可観測性)を向上させた年でもありました。ユーザーが自前でボトルネックを解析できるためのツールや、各種メトリクスの拡充を行ってきました。

アクセスの偏りを可視化する Key Visualizer の提供

その中でも、以前から待ち望まれていた機能が 2021 年に追加されました。そう Key Visualizer です。

Cloud Spanner は現在のノード数とワークロードに合わせて、全自動でシャーディングを行ってくれます。このシャーディングは、各テーブルの主キー(PK)を、一定の範囲ごとに分割し、それを各ノードに分散させています。

理想的には、全部の主キーに均等にアクセスが行くならば、均等にシャーディングさせればよいため、非常に効率的にスケールするデータベースが作れます。しかし現実のワークロードはそうはいきません。特定の PK にアクセスが集中することもあるでしょう。そのようなアクセスの偏りを可視化することができるのが、この Key Visualizer です。

図 6. は実際の Key Visualizer の画面の様子です。横軸は時間で、時系列に沿って可視化をしています。縦軸は、そのデータベースにある全てのテーブル(とインデックス)を並べて積み上げたものを表現しています。そして、ある時刻に、あるテーブルのあるキーレンジに対して、どれだけ負荷があったかを色で表現しています。負荷は、費やされた CPU 時間や、書き込み及び読み込みの量など、いくつかの指標を切り替える事ができます。ようは単純に色が明るいところは、他の部分と比較して負荷が集中しているところという意味です。

図 6. Key Visualizer の画面例

例えば図 6 の明るい部分を拡大したものが図 7 です。するとこの箇所は stock テーブルらしいということが分かりました。stock テーブルの該当キーレンジは、どうやらアクセスが他よりも集中しているようです。(この DB は EC サイトの DB を模したもので、stock テーブルは EC サイトの在庫情報を格納しているテーブルです)

図 7. Key Visualizer のある範囲だけを拡大した様子

特定の範囲にアクセスが集中していることは、必ずしも悪いことではありません。テーブルによってそもそも想定されるアクセス量は異なります。また Cloud Spanner は、負荷が高いキーレンジを更に自動的に再シャーディングして分散させる機能がありますので、多くの場合あまり問題になりません。

Key Visualizer を見るとき一番気をつける部分は、斜めに輝線が走っていないかというところです。例えば図 8. のような斜めの線です。

図 8. Key Visuazlier の画面でこれを見かけたら要注意

この線は、PK に対して時間と共にシーケンシャルにアクセスが行われていることを意味しています。Cloud Spanner のスキーマ設計に関するベストプラクティスでは、PK は連番になるような値ではなく、よく分散する値を使えと書かれています。

Cloud Spanner は一定時間同じ場所に負荷が集中すると、そこを分割して負荷分散することができます。しかしシーケンシャルにアクセスが行くということは、負荷がかかる場所が時間とともに常に移り変わってしまっており、シャーディングができない状態ということです。

シャーディングされた複数ノードの MySQL で例えるなら、負荷が常にどこか 1 シャードにだけかかっていて、更にその負荷が時間とともに(例えば毎分)違うシャードに移動していっているみたいな状態です。このようなアクセスを防ぐためには、PK は十分にアクセスがバラけるようなものを選択する必要があります。

ボトルネック解析のための各種統計情報の提供

Cloud Spanner は分散データベースであり、一つ前の Key Visualizer のところで触れたように、分散データベースに効率の良いスキーマ設計をすることになります。その後はどうでしょうか?

Cloud Spanner は RDBMS です。複数のトランザクションが並列実行され、必要に応じてロックが取得され、データの整合性を崩すことなく、処理が行われます。必要ならロック待ちをしますし、デッドロックや整合性を維持できない更新競合があったらトランザクションが abort します。

このような RDBMS 的なボトルネックを調査するために、Cloud Spanner は各種統計情報を提供するようになりました。これらをイントロスペクション ツールと呼んでいます。

図9. イントロスペクション ツールのドキュメント

イントロスペクション ツールが提供する統計情報は、テーブルに格納された一連のデータとしてアクセスが可能で、SELECT でそれを集計して調査することができます。

ドキュメントのイントロスペクション ツールの項目に、各種統計情報テーブルの詳細が書かれているので、詳しい説明はそちらに譲ります。この中でも特によく使うであろうテーブルは以下のようなものがあります。

  • クエリ統計テーブル
    クエリに関する実行統計が格納されている。具体的な SELECT について、実行回数や、CPU 時間、スキャンされた行数などの、平均値が記録される。
  • トランザクション統計テーブル
    トランザクションに関する実行統計が格納されている。トランザクションごとの、アクセスした列、COMMIT 試行回数、ABORT 回数、平均レイテンシなどが記録される。
  • ロック統計テーブル
    ロック競合についての統計が格納されている。競合が発生した PK、ロックによる待機時間、ロックの詳細が記録される。

例えば図 10. を見てみましょう。左側は Cloud Spanner のオペレーション回数のうちエラーレートのグラフです。エラーは主に abort したトランザクションが記録されますが、ある時間から急激に上昇しています。abort ということはトランザクション周りの問題なので、トランザクション統計及びロック統計を調べて、原因が見当たらないか調査することができるでしょう。この例ではロック統計からロック待機時間が顕著に上がっており、トランザクション競合の線で調べていけそうだと分かります。

図 10. エラーレートが上がっている(abort している)時間帯をロック統計で調査した例

ここから先のチューニングやボトルネック解析は Cloud Spanner 固有の話ではなく、RDBMS で一般に必要となるたぐいのものです。Cloud Spanner はこのようなメトリクスを拡充していくことで、より開発者や運用者の方に使いやすいデータベースを目指していっています。

冬休みの宿題の宿題

さて最後に、1〜4 時間目までで触れられなかったその他新機能について、冬休みの宿題としてここで紹介したいと思います。

BigQuery から Cloud Spanner への接続

Cloud Spanner は外部サービスとの連携も強化しています。

この機能は BigQuery 側の機能なので、Cloud Spanner のリリースノートには載っていないのですが、先日、BigQuery の連携クエリ(Federated Query)が、Cloud Spanner にも対応しました。

これにより、BigQuery から直接 Cloud Spanner 上のデータに対してクエリをかけることができるようになりました。方法はこれまで BigQuery から Cloud SQL に対してできていたものと同じく、 EXTERNAL_QUERY に続いて、直接 SELECT を記述できます。

図 11. BigQuery のコンソールから Cloud Spanner に SELECT を投げている様子

Cloud Spanner をサービスやシステムのバックエンド DB として使う際、分析目的でそのデータを BigQuery に流し込みたいという要望は、これまでも多く上がっていました。

JSON 型への対応

Cloud Spanner のデータ型として、新たに JSON 型がサポートされました。

MySQL や PostgreSQL といった RDBMS はもちろん、BigQuery でも JSON サポートが進んでいます。それに伴い、Cloud Spanner でも JSON 対応を求める声が大きくなってまいりました。今回 Cloud Spanner が JSON 型をサポートしたことで、より柔軟に様々なユースケースで Cloud Spanner を使っていただけるものと考えております。

Terraform との統合

Terraform から Google Cloud Terraform プロバイダ経由で Cloud Spanner の操作が可能になりました。

Terraform は HashiCorp 社による Infrastructure as Code (IaC) ツールで、様々なクラウド環境や仮想環境にて、構築や変更及びバージョニングを行うことができるツールです。マルチクラウド環境をお使いの方には、Terraform を利用されてる方も多いと思われます。

Terraform が Cloud Spanner に対応したことで、Terraform 経由で Cloud Spanner のノードやデータベースの管理を行うことができるようになりました。もちろん 2 時間目で紹介した、1 ノード未満のインスタンスにも対応しており、処理ユニット指定で構築することもできます。

おわりに

今回は 2021 年の Cloud Spanner を振り返るということで、簡単にさらっと流しました。年が開けたら、個々の特徴や機能について詳細に解説する記事を書いていこうと考えております。もしこういう記事が欲しいなどフィードバックありましたら教えて下さいね!

ちょっと早いですが、それでは良いお年を!

--

--