アンチパターンから学ぶ!Cloud Spanner あるあるクイズ

Yuki Iwanari
google-cloud-jp
Published in
10 min readDec 16, 2019

--

この記事は Google Cloud Japan Customer Engineer Advent Calendar 2019 の 13 日目の記事です。

本記事では、Cloud Spanner を初めて使う場合にハマってしまいがちなポイントを、クイズ形式でまとめてみました。Cloud Spanner を適切に使うために、思わぬ落とし穴にはまらないように、参考資料などにも目を通してください。

Cloud Spanner とは??

Cloud Spanner は、スケーラビリティと強整合性を兼ね備えた、エンタープライズレディーなデータベースです。急峻なスパイクに対しても瞬時に DB の性能を変更できるため、API サーバに近い感覚で、DB をスケールアウト、スケールインさせることが可能です。

そんな Cloud Spanner ですが、うまく使いこなすためには、Cloud Spanner の特性を考慮した設計が必要になります。Cloud Spanner では、うまくデータを分散させつつデータローカリティもうまく使う必要があり、そのためには、スキーマ設計が鍵となります。

Cloud Spanner をうまく使うための参考資料

Cloud Spanner 公式ドキュメント
なんと言っても公式ドキュメント。「ベストプラクティス」は必見です。また、「ゲーム データベースとして Cloud Spanner を使用する場合のベスト プラクティス」は、ゲーム業界のみならず、Cloud Spannerを使う際の Tips が散りばめられています。

ゲーム開発が変わる!GCPゲームインフラ実践ガイド
ゲーム業界のエンジニアが執筆した(私も協力として参加させていただきました)、エンジニア向けの技術書。本書の中で、コロプラさんの章にて、実践で培った Cloud Spanner を使う際のノウハウが解説されています。

ポイントをキャッチアップできましたでしょうか?

では、早速行ってみましょう!

第1問 〜初級編〜

以下のスキーマ、データで、問題になりそうなポイントはどこでしょうか?

CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024) NOT NULL,
LastName STRING(1024) NOT NULL,
LastAccess TIMESTAMP NOT NULL,
) PRIMARY KEY (SingerId);
CREATE INDEX SingersByLastAccess ON Singers(LastAccess);

【解説】
Cloud Spanner は、ホットスポットを作らないようにスキーマを設計することが非常に重要です。ホットスポットとは、特定の Spanner ノードにリクエストが集中してしまう現象を指します。

ホットスポットが起きている状態(公式ドキュメントより引用)

ホットスポットという観点で見てみると、上の設計でどのような点が問題があるでしょうか?

1つ目は、 Primary Key (以下、PK) です。データを見てみると、単調増加する値を PK として選択しています。
Cloud Spanner では、PK の辞書順にレコードが並んでおり、スプリットに分割されて Spanner ノードに割り当てられています。単調増加する値を PK として利用すると、新しいレコードは最後のスプリットに追加されてしまいます。そのため、PK にシーケンシャルな値を選択するのはアンチパターンとなっています。

上記の事象を避けるために、 Cloud Spanner では、十分に分散する PK を選択する必要があります(UUID v4 を推奨)。また、その場合は、現状の INT64 ではバイト数が足りないので、 STRING(36) など、UUID v4 を格納するのに十分なデータ型を選択しましょう。

2つ目は、インデックスです。 「最後にログインしたユーザ XXX 名」などをクエリするユースケースを想定して、インデックスを作成したと考えられます。
Cloud Spanner では、テーブルと同じ方法でインデックスデータを格納します。そのため、テーブルの設計で考慮すべきポイントの多くは、インデックスについても当てはまります。つまり、インデックスでもホットスポットが発生しないように考慮する必要があります。

インデックスのイメージ

対策については、「値が単調に増加または減少する列へのインターリーブされたインデックスの使用」が参考になります。 値が単調に増加または減少する列に、インターリーブされていないインデックスを作成しないようにしましょう。

なお、主キーの設計については、以下が(とても)参考になります。

第2問 〜中級編〜

以下のシチュエーションで、問題となりうるポイントはどこでしょうか?

新規サービスのローンチに向けて、以下のようなスキーマ設計としました。=================================================
CREATE TABLE Players(
PlayerId STRING(32) NOT NULL,
Name STRING(1024) NOT NULL,
...
Level INT64 NOT NULL,
) PRIMARY KEY (PlayerId);
CREATE INDEX PlayersByLevel ON Players(Level);
=================================================
また、既存タイトルの情報から、下表のようなデータを使えば、妥当な負荷テストができそうであることが分かっているため、以下のデータを使って負荷試験を実施しました。
テストデータ

【解説】
信頼性の高いデータを使って負荷試験を実施しており、一見すると問題がないように見えますが、どこにリスクが潜んでいるでしょうか?

実は、 Level のインデックスがホットスポットになる可能性があります。定常状態のデータを使って負荷試験を実施する場合、Levelのデータが適度に分散している場合は特に問題がないかもしれませんが、サービス開始時点だと、すべてのユーザが 1 から始まってしまう可能性が高いでしょう。

サービス開始時点のデータ

定常状態だけでなく、リリース時を想定したシナリオの負荷試験を実施することで、このようなケースを見つけることができます。また、この状態を解決するには、アプリケーション側でシャードする、インデックスをインターリーブする、初期状態ではインデックスを張らない、といった対策が考えられるでしょう。

また、(本件とは直接関係がないですが)負荷試験という意味では、実データを利用して負荷試験を実施することも非常に重要なポイントです。 前述の通り、 Cloud Spanner のスキーマがベストプラクティスに則っているかどうかを確認する場合に、意味のないダミーデータを使ってしまうと、性能が出なかったり、逆にホットスポットを負荷試験で見過ごしてしまうケースも出てくるでしょう。

第3問 〜上級編〜

さて、最後です。以下の状況で、問題となるポイントはどこでしょうか?

新規サービスのリリースに備え、スキーマに問題がないことを確認し、リリース時および定常状態のシナリオを想定した負荷試験も作成しました。
リリースまであと一ヶ月、すべての負荷試験を実施し、パフォーマンスに問題ないことを確認できたので、リリースに向けて負荷試験時のデータを削除(DELETE)し、準備を完了しました。

【解説】
初期リリースおよび定常状態のシナリオを想定した負荷試験を実施し、パフォーマンスに問題がないことが確認できていれば、準備万端のように見えます。

ここでポイントなのは、「リリース一ヶ月前に負荷試験を実施し、準備を完了した」という点です。

Cloud Spanner では、データベースのサイズが大きくなると、データがスプリットという単位に分割され、別のサーバーに割り当てられます。負荷試験を実施したことで、負荷試験実施時点ではスプリットが十分に作成されているため、うまく負荷分散される状態(ウォーム状態)になっています。

しかし、負荷試験を実施した後にしばらく時間が経つと、有効なデータのないスプリットは時間が経つとマージされてしまうため、リリース時点では使用可能なスプリットが足りない状態になってしまう(コールド状態)のです。

この状態を回避するには、負荷試験をリリース直前( 2 日前目安)に実施する必要があります。なお、Cloud Spanner のウォームアップについては、公式ドキュメントのベストプラクティスで詳しく説明されています。

なお、このようなケースは、リリース時点で最大のリクエストが想定される場合(例:ゲームタイトルのリリース時)に該当します。徐々にリクエストが増えていく場合であれば、負荷に応じてスプリットが適切に作成され、うまく負荷分散されるため、上記の事象が起こるリスクは低いでしょう。

おわりに

本記事では、 Cloud Spanner を利用する際にハマってしまいがちなポイントを、クイズ形式でご紹介しました。

繰り返しになりますが、 Cloud Spanner の設計では、「適切に分散させること」「適切にデータローカリティを保つこと」が非常に重要となります。Cloud Spanner をうまく使いこなして、 DB にも伸縮自在のスケーラビリティを手にしましょう!

次は、 Hiroki Tanaka による「GKE network 基礎 VPC native cluster と Route based cluster」です。
お楽しみに!

--

--

Yuki Iwanari
google-cloud-jp

Customer Engineer in Google Cloud. All views and opinions are my own.