当記事は みずほリサーチ&テクノロジーズ × G-gen エンジニアコラボレーション企画 で執筆されたものです。
G-gen の片岩です。Google Cloud の Cloud Spanner について徹底解説します。Cloud Spanner は強整合性を持ちながらグローバルな負荷分散が可能なサービスです。高い可用性、データの完全性が求められる金融分野での活用が見込まれるデータベースです。
Cloud Spanner の概要
Cloud Spanner とは
Cloud Spanner は強整合性を保証する RDB(リレーショナルデータベース)の特徴とグローバルに水平スケーリングできる NoSQL データベースの特徴を併せ持つデータベースです。そしてダウンタイムが最小限であり運用負荷の少ないフルマネージドのデータベースでもあります。
Cloud Spanner は強整合性 (RDB の強み) と、スケーラビリティ (NoSQL の強み) のいいとこどりのアーキテクチャを兼ね備えており、他クラウドにも類似サービスのない、ユニークなデータストアサービスです。
- 参考 : Cloud Spanner
強整合性と結果整合性
強整合性とは、読み取り処理で必ず最新の書き込み情報を読み取れる性質です。例えばECサイトでは必ず最新の在庫状況を取得できなければ、在庫がないにもかかわらずお客さまから商品の注文を受け付けてしまいます。勘定、決済などを取り扱う場合にも強整合性が必要なことは想像に難くないと思います。
対照的に、最新情報の読み込みを保証しない性質が結果整合性です。NoSQL データベースは、スケーラビリティとパフォーマンスが高い(後述)反面、結果整合性を持ちます。例えば自分の投稿にお気に入りをした人の数など、結果整合性で十分なデータでは NoSQL データベースの特性を十二分に活用できます。
水平スケーリング
NoSQL データベースの内部ではデータを分割して保存するため、簡単に水平スケーリングすることができます。
一方、RDB ではデータベースを分割しないため水平スケーリングは難しく、垂直スケーリングしか取れないため、性能上限に抵触しやすいです。
Cloud Spanner は強整合性という RDB の特徴を持ちながら、NoSQL の特徴である水平スケーリングも実現する、ユニークなデータベースサービスです。
インターフェイス
SQL
Cloud Spanner のデータは SQL で操作することができます。SQL の方言として GoogleSQL と PostgreSQL のいずれかから選択することができます。選択はデータベース作成時に行います。
GoogleSQL と PostgreSQL は完全互換ではありませんが、ほとんど同様に利用できます。開発チームが PostgreSQL に慣れていたり、あるいはクライアントとして psql などの PostgreSQL エコシステムのツールを利用したい場合は PostgreSQL を選択することが望ましいです。
API
SQL の他にも、各プログラミング言語用のクライアントライブラリを使ったり、Rest API / gRPC を使ったデータの読み書きを行うことができます。
- 参考 : トランザクションについて
- 参考 : トランザクション外部の読み取り
- 参考 : ミューテーションを使用してデータを挿入、更新、削除する
クライアント
Spanner では以下のようなユーザーインターフェイスを通じて SQL を実行したり、ミューテーション(API コールによるデータの更新)を実行したりすることができます。
- Google Cloud コンソール (Spanner Studio)
- 各言語用の Spanner クライアントライブラリ (Cloud SDK)
- REST API
- RPC API
- PostgreSQL クライアント (PostgreSQL Interface モードの場合)
psql などのコマンドラインで Spanner に接続する場合、PGAdapter というプロキシソフトウェアを経由して接続します。PGAdapter は JVM の動作するスタンドアロンプロセスあるいは Docker イメージとして提供され、クライアントのローカル環境やサイドカーコンテナとして起動されます。psql 等のクライアントからこの PGAdapter に対して接続すると、PGAdapter は IAM 認証を経て、インターネット経由(gRPC プロトコル)で Spanner インスタンスに接続します。
ユースケース
Cloud Spanner が適したケース
以下のいずれかにあてはまる場合に Cloud Spanner が有力な選択肢となります。
- 強整合性とスケーラビリティがどちらも必要な場合
- ダウンタイムを極力減らしたい場合
- データベースの運用負荷を軽減したい場合
代表的な事例
Cloud Spanner を利用した、代表的な公開事例をご紹介します (Google Cloud 社の Web サイト)。
- みんなの銀行 の勘定系システムで利用されています。東阪両現用を実現するデータストアとして Cloud Spanner を活用しています。
- ポケモンGo で利用されています。1 秒あたり 100 万件近いトランザクションを処理することも可能です。
- メルペイ で利用されています。信頼性の高い決済処理を数百万のユーザーに 24 時間 365 日 提供しています。
類似サービスの使い分け
Google Cloud が提供する RDB のサービスには Cloud Spanner のほかに Cloud SQL と AlloyDB があります。
Cloud SQL
Cloud SQL は MySQL、PostgreSQL、SQLServer を扱える RDB です。利用規模が小〜中規模な場合、また非常に大きなスループットを要しない場合は、コスト面で優位な Cloud SQL で十分と言えます。
AlloyDB
AlloyDB は 99.99% の可用性(1年間における停止時間の合計が約53分以内)を保証する、パフォーマンスに優れたデータベースで、AWS の Amazon Aurora に相当するサービスです。
PostgreSQL 完全互換のため利用可能なライブラリが充実しています。利用規模が中〜大規模で、高パフォーマンスが要求され、PostgreSQL の豊富なライブラリを利用したい場合は AlloyDB が望ましいと言えます。
Cloud Spanner
Cloud Spanner ではマルチリージョン構成の場合に 99.999 % の可用性(1年間における停止時間の合計が約5分以内)を保証します。
スケーラビリティにも優れているため、グローバルにサービスを展開したい場合や、サービスをほぼ無停止で展開したい場合に Cloud Spanner の利用を検討します。
料金
Cloud Spanner は割り当てたコンピューティング容量と使用しているストレージ量に対して課金されます。 例として 100 処理ユニット、ストレージ使用量を 100GB で 1 ヶ月間フル稼働すると、約 16,795 円 / 月です(2023年2月時点、東京リージョン、135円/ドル)。
同一のコンピューティング容量であっても、シングルリージョンとマルチリージョン、さらにアメリカとアジアとヨーロッパをまたいだマルチリージョンで単価が異なります。
最新の利用料金は以下の公式ページでご確認ください。また、公式の見積もりツールで料金が試算できます。
また、Cloud Spanner には確約利用割引の仕組みがあります。1 年間または 3 年間の利用を確約することで最大 40% の割引を受けることができます。詳細は以下のドキュメントをご参照ください。
- 参考 : Spanner CUD の料金
インスタンスと構成
インスタンス
Cloud Spanner はインスタンスの単位で管理します。
Cloud Spanner におけるインスタンスは、データベースの基盤となる仮想サーバー群のことです。インスタンスごとに構成(リージョン構成またはマルチリージョン構成)とコンピューティング容量を選択します。
リージョン構成、マルチリージョン構成
リージョン構成では、指定したリージョン内の複数のゾーンにクラスタが展開されます。マルチリージョン構成に比べて、コストパフォーマンスに優れています。
マルチリージョン構成では、指定した複数のリージョンにまたがってクラスタが構成されます。リージョン構成に比べて、可用性や、複数の国や地域からアクセスされる際のレイテンシに優れています。
リージョン障害への対応が必要な場合や、東阪両現用のように複数のリージョンにまたがって高いパフォーマンスが要求される場合はマルチリージョン構成を選択します。
また、SLA にも違いがあります。リージョン構成では99.99%、マルチリージョン構成では99.999%の可用性 SLA が設定されています。
各構成においては、選択する地域によって、どのリージョンにレプリカ(サーバー)が配置されるかが決まります。詳細は後述の「リージョン構成 / マルチリージョン構成それぞれにおけるレプリカの内訳」の項をご参照ください。
なおインスタンス構成は、運用開始後でもダウンタイム無く変更できるため、最初はリージョン構成から開始し、利用規模が大きくなってからマルチリージョン構成に変更することも可能です。
- 参考 : インスタンスを移動する
コンピューティング容量
インスタンスのコンピューティング容量は、処理ユニット(処理単位、processing units)の割り当てで決定します。処理ユニットの値によって、データのスループットや秒間クエリ数、ストレージの上限が決まります。
また、テーブル数の上限も処理ユニットによって決定されます。10ユニット毎に1テーブルの上限があります。
処理ユニットの下限値は 100 で、100 処理ユニット単位でコンピューティング容量を指定できます。また 1,000 処理ユニットを 1 ノードと呼び、1,000 処理ユニット以上を指定したい場合はノード単位でコンピューティング容量を指定することになります。
- 参考 : コンピューティング容量、ノード、処理単位
読み取り方式
Cloud Spanner では強力な読み取りとステイル読み取り、そしてトランザクションという3種類の読み取り方法があります。
デフォルトの読み取り方式は強力な読み取りです。強力な読み取りでは強整合性を持った読み取りが可能な反面、読み取りの都度最新のデータであるかチェックするため、内部通信が発生しレイテンシが大きくなります。
必ずしも強整合成が必要のない読み取りの場合はステイル読み取りを使用します。stale は新鮮ではない、というニュアンスの言葉です。
ステイル読み取りではレプリカ自身が持つ最新のデータであるかのチェックをスキップするため、より高速な読み取りが可能となります。
- 参考 : トランザクション外部の読み取り
最後に、トランザクションは、ロックに依存する書き込みと読み込みを同時に行う場合や、複数の読み取りで一貫性を持たせたい場合に用います。以下のドキュメントを参照してください。
- 参考 : トランザクションの概要
バックアップ
Cloud Spanner のバックアップでは、バックアップと復元機能、もしくはインポート/エクスポート機能が使用できます。
バックアップと復元
バックアップと復元(back up and restore)機能では、インスタンスと同じ地理的ロケーションにバックアップを保管することができます。
また、バックアップはトランザクションの処理には直接関係しないため、インスタンスのパフォーマンスには影響しません。
バックアップ機能は手軽に利用できる反面、以下のような制約があります。
- バックアップの保存期間は最長 1 年間
- インスタンス内のリソースになるため、同じ構成のインスタンスを作成する場合を除いてデータの持ち出し不可
基本的にはバックアップと復元 機能の利用を検討し、上記の制約が許容できない場合はインポート/エクスポートを使用します。
- 参考 : バックアップの概要
インポート/エクスポート
インポート/エクスポートでは、Cloud Storage の CSV ファイルや Avro ファイルの読み取り/書き込みが可能です。
バックアップはファイルとして出力されるので上記の形式に対応した外部のデータベースにデータを持ち出したり、ファイル自身のライフサイクルを管理して1年以上保管することができます。
「バックアップと復元」機能と「インポートとエクスポート」機能の比較については、以下のドキュメントもご参照ください。
ポイントインタイムリカバリ
マスタデータを誤って削除した場合など、一部データのみ復元したい場合には、ポイントインタイム リカバリ(PITR)を利用できます。
最長7日間の任意の時刻のスキーマとデータを復元することができます。
運用
従来のデータベースであれば、データ量が膨大になり 1 つのデータベースに収まりきらなくなると、以下のように複数のデータベースにデータを分割するといった作業が発生しました。
- ユーザー ID が a 〜 m から始まる場合はデータベース 1 を利用
- ユーザー ID が n 〜 z から始まる場合はデータベース 2 を利用
Cloud Spanner では全自動でデータの分割処理が実施されるため、上記のような作業は発生しません。必要に応じて以下の作業を行うだけとなります。
- CPU 使用率をモニタリングする
- ノードの追加や削除を実施する
- バックアップ / リストアを実施する
このように運用負荷が少ないことも Cloud Spanner の強みです。
データ処理の仕組み
ここからは Cloud Spanner の内部的な仕組みをご紹介します。まずは大量のデータを高速に処理する仕組みです。
シャーディング
Cloud Spanner では PK のレンジに沿ってデータがいくつかに分割 (シャーディング) されてストレージに保存されます。この分割されたデータをスプリットと呼びます。
各ノードは、それぞれ割り当てられたスプリットの読み込み処理や書き込み処理を担当します。ノードを増やすと 1 ノードあたりのデータ量が減り、それだけ負荷分散できることになります。
各データが均等にアクセスされる場合は、各スプリットのサイズも概ね均等になります。
各データが均等にアクセスされない場合、たとえば上記の図で y や z から始まるデータのアクセス量が多い場合は、各ノードの負荷が均等になるように、以下のように自動的にリシャーディングされます。
一時的なリシャーディングは問題ありませんが、継続的なリシャーディングが発生するとデータベースに無駄な負荷がかかってしまいます。たとえば上記の図で z から開始するデータだけが増え続けてしまうと、ノード 3 のみに負荷が集中することになり、継続的なリシャーディングが発生してしまいます。
特定のノードに負荷が集中して継続的なリシャーディングが発生しないよう、データベースのスキーマ設計時はご留意ください。
インターリーブ
詳細は後述しますが、単一リージョン構成の場合はデータが 3 つのゾーンに 3 重に冗長化されています。以下は 2 つのテーブル①とテーブル②が 3 つのゾーンで冗長化されるイメージです。
それら 3 のゾーンのうち読み書きを実行するリーダーがスプリットごとに選ばれます。特段の指定をしない場合は、テーブル①とテーブル②はそれぞれ独立してスプリットに分割されます。
たとえば上の図の PK が b からはじまるデータに対してテーブル①とテーブル②に更新処理を実行すると、更新処理はリーダーを通して実行されるため、テーブル①ではゾーン a で処理し、テーブル②ではゾーン b で処理するといった事象が発生します。
このようにJOIN したいテーブルのノードが異なると、ノード間の通信が必要になり、オーバーヘッドが発生してしまいます。
このオーバーヘッドを回避するために、関連するテーブルのデータを物理的に連続した同じ位置に配置することができる仕組みをインターリーブと呼びます。インターリーブを使用することにより、JOIN 時に異なるノード間の通信が発生することを抑えることができます。
強整合性とスケーラビリティの両立
次にグローバルに強整合性を担保できるユニークな仕組みを見ていきましょう。
3 種類のレプリカ
Cloud Spanner のインスタンスは、読み書きレプリカ、読み取り専用レプリカ、ウィットネス レプリカの 3 種類のレプリカから構成されます。
- 読み書きレプリカ は読み書きすることができます。唯一書き込みが処理できます。
- 読み取り専用レプリカ も読んで字のごとく読み取りのみすることができます。
- ウィットネス レプリカ は読み取りしないで、書き込みの commit を決める投票(後述)のみ参加するレプリカです。
読み書きレプリカは複数存在し、そのうちの 1 つが リーダーレプリカ となります。
詳細は後述しますが、リーダーレプリカは書き込み処理において中心的な役割を果たします。
レプリカの種類 | リーダー可否 | 書き込み | 読み込み | 投票 |
---|---|---|---|---|
読み書き | ◯ | ◯ | ◯ | ◯ |
読み取り専用 | x | x | ◯ | x |
ウィットネス | x | x | x | ◯ |
書き込み(commit)の仕組み
Cloud Spannerは commit の仕組みに特徴があります。
- すべての書き込みリクエストがリーダーレプリカに送信されます。
- リーダーレプリカは書き込みリクエストがあったことをログに記録します。
- リーダーレプリカは読み書きレプリカとウィットネスレプリカに書き込みリクエストを転送します。
- 書き込みリクエストを受け取ったレプリカは書き込みを実行後、リーダーレプリカに投票を返却します。
- 投票が過半数のレプリカから返却されるとリーダーレプリカはcommit 完了とみなします。
- リーダーレプリカがcommitを完了とみなした後も、書き込みリクエストを受け取ったレプリカは書き込みを継続し完了します。
分散データベースで利用される 2 フェーズコミットでは投票可能なレプリカの すべて が書き込みの commit に同意した時点で、書き込みが commit されます。
対して Cloud Spanner では投票可能なレプリカの 過半数 が書き込みの commit に同意した時点で、書き込みが commit される点が特徴です。
なお、リーダーレプリカは 10 秒間隔で読み取り専用レプリカを更新します。ステイル読み取りでは何秒前のデータを読み取るかが指定できますが、15 秒とすることが推奨されています。これは前述の 10 秒間隔の更新を想定したものです。
読み取りの仕組み
強力な読み取り (最新データを読み取る必要がある場合)
レプリカは自身が持つデータが最新であるか判断するために、以下の処理を行います。
- レプリカは読み取りリクエストを受信します。
- レプリカはリーダーに読み取りリクエストを送信します。
- リーダーは、対象行の最新トランザクションのタイムスタンプを応答します。
- レプリカは自身が持つデータが最新であるか判断します。
- 行が最新の場合、レプリカは結果を返すことができます。
- 最新でない場合は、リーダーからの更新情報を受け取ってから応答します。
なお、読み書きトランザクションに含まれる読み取りはこの流れではありません。書き込みが必要なトランザクションでは直接リーダーレプリカがトランザクションを処理するためです。
ステイル読み取り
前述のステイル読み取りではリーダーレプリカに最新のデータかどうか問い合わせる処理をスキップすることで、強整合性を犠牲にレイテンシーを低減することができます。
たとえば 最新時刻から見て 15 秒前のデータで問題なければ、15 秒前のデータをリクエストします。レプリカはリーダーに最新情報を問い合わせる必要なく低レイテンシでデータを返すことができます。
リージョン構成 / マルチリージョン構成それぞれにおけるレプリカの内訳
リージョン構成の場合は以下の構成になります。
- 1 つのリージョンの 3 つの異なるゾーンそれぞれに読み書きレプリカ
マルチリージョン構成、たとえば asia1(東京 / 大阪 / ソウル)の場合は以下の構成になります。
- 東京に 2 個の 読み書きレプリカ
- 大阪に 2 個の 読み書きレプリカ
- ソウルに 1 個のウィットネスレプリカ
大陸間をまたぐマルチリージョン構成、たとえば nam-eur-asia1(北アメリカ / ヨーロッパ / アジア)の場合は以下の構成になります。
- アイオワに 2 個の 読み書きレプリカ
- オクラホマに 2 個の 読み書きレプリカ
- ベルギーに 2 個の読み取り専用レプリカ
- 台湾に 2 個の読み取り専用レプリカ
- サウスカロライナに 1 個のウィットネスレプリカ
データブースト
Cloud Spanner のデータブースト(Data Boost)機能は、読み取り専用のコンピュートリソースを既存クラスタとは別で割り当てることで、分析用途などの読み取りワークロードを分離することができる仕組みです。
この機能を用いることで、通常のアプリケーションが使っている Spanner のリソースに影響を与えることなく、分析用のクエリを発行することなどが可能です。この機能を有効化すると、必要に応じて読み取り専用のコンピュートリソースが臨時で割り当てられ、Spanner のストレージにアクセスできます。
利用例として「BigQuery から Cloud Spanner への連携クエリ(Federated query)のために利用する」「レポート作成やデータエクスポートのための定期ジョブに利用する」などが挙げられます。
当機能を利用すると、一時的に割り当てられた処理ユニットに対して料金が発生することにご注意ください。
- 参考 : データブーストの概要
片岩 裕貴 (記事一覧)
クラウドソリューション部 クラウドディベロッパー課
2022年5月にG-genにジョインした和歌山県在住のエンジニア。興味分野はAI/ML。2024年にGoogle Cloud認定資格全冠達成。最近は子供と鈴鹿サーキットや名古屋のレゴランドに行ってきました。