[GCP]Cloud Spanner

# 1. 概要
- フルマネージド(**セキュリティ対応・メンテが自動**)なRDB
- 独自DBエンジンの分散SQL(NewSQL).**普通にSQL使える**
- **最大99.999%の可用性**
    - 単一リージョン構成: 99.99%
    - マルチリージョン(東京 x 大阪とか)構成: 99.999%
- **ノード数の増減によるスケールイン/アウトが可能**
    - Autoscalerで負荷状況に基づいてオートスケーリング可能
- **デフォルトでシャーディングが行われ**、**ルーティングもSpanner持ち**なので、サーバーアプリケーション側で接続先を制御する必要なく、単一のエンドポイントに接続すればOK
- Spannerでは、シャーディングによるレコードの分割単位(一般的にはシャードと呼ばれるもの)はスプリットと呼ばれ、**レコードの主キーの値に基づいて分割**される
    - **ノード数や負荷状況に応じて自動的にいい感じにノードとスプリットの紐づきを変更**してくれる
    - とはいえ、**アクセスが集中するレンジの偏りが代わり続けると結局負荷分散できない** ので、Spannerのベストプラクティスに従う必要あり。
- **トランザクションをサポート**
- Go含む主要言語のライブラリ(APIやSQLを利用したデータの操作が可能)あり
- 1インスタンス内に100個のDBを作成可能
- DB単位でバックアップ可能で、同一リージョンのインスタンス(同一インスタンス含む)にリストア可能
- **バックアップから直接SELECT可能**
- CLIツールspanner-cliあり(MySQLのmysql, PostgreSQLのpsqlに相当)　　　　
- **[利用料金](https://cloud.google.com/spanner/pricing?hl=ja)**
    - 以下項目に対して課金され、それぞれリージョン毎に価格設定が違う。
        - コンピューティング容量(DBサーバーのCPU,メモリ,ストレージ容量)
        - ストレージ使用量
        - ネットワーク使用量
    - 比重としてはコンピューティング容量が大きそうな感じ(1ノードあたり1時間$1くらい。つまり日に$24,月に$720かかる)がする。

# 2. インスタンス・リージョン・ノード・ストレージ・ゾーン・スプリット・レプリケーションの関係
参考文献をもとにした自分自身の理解・解釈をまとめておく。
マルチリージョンになるとややこしいので、単一リージョンの話で。

**関連イメージ図**
※「API」はそれらしき情報ソースがなかったので、実際と乖離している可能性が高い

![[GCP]CloudSpanner.drawio (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59542/bef3e1c4-6c9b-403d-c99b-563e8a6c2c8c.png)

以下、要素の解説。

## 2.1. インスタンス
「Cloud Spanner」で単純に「インスタンス」と呼ぶのは、
**以下ひとまとまりの設定を施して動作している「Cloud SpannerのDBシステムの実体」** のこと。

- インスタンス名(表示に使われるだけ)
- インスタンスID
- リージョンの設定
- コンピューティング容量

## 2.2. コンピューティング容量
各ゾーンで共通な以下のリソース量を決定する単位のこと。

- 起動する全ノードのCPUリソースの合算・メモリリソースの合算
- ストレージ容量

その具体的な単位は「ノード」 or 「PU(処理単位, 処理ユニット)」で、1ノード = 1000PU 換算になる。

なお、1ノードにおいて実際にCPU・メモリがどれだけ割り当てられるのかは非公開情報である模様。
ストレージについては、1ノードあたり4TB割り当てられる(2022/10/18現在)

## 2.3. ノード
「DBサーバーのコンテナインスタンス」であり、「読み取り・書き込み・コミット」のみを行う。
DBのレコードが保存されているのはストレージである。

Cloud Spannerのインスタンスに対してコンピューティング容量を設定(更新)すると、
同インスタンスで設定しているリージョン内の3ゾーンそれぞれで、以下が行われる。

- 新規ノードの起動 or 既存ノードの停止
- 各ノードの担当スプリットの変更
- ストレージ容量の変更

各ノードの担当スプリットの変更は、管理者側の「コンピューティング容量」の設定による「ノード数の変化」以外にも、
「負荷状況」、「データ数」によるCloud Spanner側の「スプリット数の変化」によっても発生する。

## 2.4. ストレージ
Cloud SpannerのDBのレコードが保存されるところ。

## 2.5. スプリットとは
レコードは、そのテーブルの主キーとなるカラム値の範囲に基づいて、分割されて保存される。
(分割時に物理的な位置が離れることあり)
この分割単位をスプリットと呼ぶ(RDBでいうところのシャードである)。

スプリットの数はテーブル毎に異なり、「データ数」や「負荷状況」によってCloud Spanner側で動的に変更される。

## 2.6. レプリケーション
DBのデータのコピー処理であり、Cloud Spannerでは「Paxos」という仕組みが使われている。

Spannerインスタンスで単一リージョンの設定をした場合、それぞれのスプリットが3ゾーン間でレプリケーションされる。
レプリケーション観点で見ると、それぞれのスプリットが「レプリカ」である。
「Paxos」により、3ゾーンのレプリカのうち、1ゾーンのレプリカはリーダーレプリカに設定される(10秒くらいでリーダーはうつる模様)。
リーダーレプリカは書き込み、読み込みはそれ以外の2ゾーンのレプリカ(フォローレプリカと呼ばれることもあるっぽい？)が担当する。

# 2. インスタンス構成
データベースの地理的な場所とレプリケーションの定義。
大きく以下の3つの区分がある。
- リージョン: 全てのリソース群を単一のリージョンにおさめる
- デュアルリージョン: リソース群を単一の国の中の2つのリージョンにまたぐ
- マルチリージョン: リソース群を複数のリージョンにまたぐ

GCPで用意されているインスタンス構成(=基本インスタンス構成)のリストは、[Regional, dual-region, and multi-region configurations](https://cloud.google.com/spanner/docs/instance-configurations)に記載されている。

## 2.1. カスタム構成
基本インスタンス構成に対して、オプションでリードレプリカを追加したインスタンス構成を定義でき、これはカスタム構成と呼ばれる。
[Regional, dual-region, and multi-region configurations](https://cloud.google.com/spanner/docs/instance-configurations)を確認した限りでは、インスタンス構成によってリードレプリカを追加できる/できないがある模様。

## 2.2. インスタンス構成の変更
Spanner稼働中に変更可能で、ダウンタイムは発生しない(参考: [Move an instance](https://cloud.google.com/spanner/docs/instance-configurations#move-instance))

# 3. スキーマ設計のベストプラクティス
**参考**

https://cloud.google.com/spanner/docs/schema-design?hl=ja

ざっくりとは、単調に増加するカラムを主キーにしない (INSERTが最新のスプリットに集中することになるから)こと
対策としては、

**主キー(複合キー含む)としたいカラム値から生成したハッシュ値を主キーにする** 

こと。

**インターリーブ**

親テーブルのレコード配下に子テーブルのレコードを物理的に配置できるというもの.
クエリのパフォーマンスが大幅に向上するらしい

# 参考

**↓Cloud Spannerについての全体的な説明ががめちゃくちゃわかりやすい**
どうやって構築すればよいのか？負荷増減に対して何すればよいか？も書いてある

https://lp.cloudplatformonline.com/rs/808-GJW-314/images/Database_OnAir_q2_0409_Session.pdf

https://dev.classmethod.jp/articles/cloud-spanner-free-trial-instances-are-now-generally-available/

https://cloud.google.com/spanner/docs/schema-design?hl=ja

↓スプリット数の制御について

https://cloud.google.com/blog/ja/topics/developers-practitioners/what-cloud-spanner

↓単一リージョンのレプリカの動きについて

https://qiita.com/ototonari/items/e6d24c4a05a27fee1cce

↓レプリカの動き関連

https://yuichi1004.hatenablog.com/entry/2017/02/26/162204#Spanner-%E3%81%AF-Datastore-%E3%81%AB%E4%BC%BC%E3%81%A6%E3%81%84%E3%82%8B

↓Terraformを利用したSpanner DB、テーブル作成
https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/spanner_database

## Google Cloud 公式ドキュメント類
### ゲーム開発にSpannerを使用する場合のベストプラクティス

https://cloud.google.com/architecture/best-practices-cloud-spanner-gaming-database?hl=ja

### 実際の操作を試す

**Google CloudコンソールからのDB作成とクエリ実行**

https://cloud.google.com/spanner/docs/create-query-database-console?hl=ja

**gcloud CLIからのDB作成とクエリ実行**

https://cloud.google.com/spanner/docs/getting-started/set-up?hl=ja

https://cloud.google.com/spanner/docs/getting-started/gcloud?hl=ja

**ライブラリを利用したGolangでのDB作成とクエリ実行**

https://cloud.google.com/spanner/docs/getting-started/go?hl=ja