Cloud Spannerのことをﾁｮｯﾄ理解できる記事（GKE & Cloud Spanner入門勉強会 参加レポート）

## ご挨拶

はじめましての人ははじめまして。[がっちゃん](https://twitter.com/gatchan0807)です
今回は2年ぶりぐらいにQiitaに記事を投稿します

記事の内容としては、昨日参加したGoogle主催の勉強会のレポートで、GKE（k8s）とCloud Spannerの仕組みについての話を自分なりにまとめたものです

もし間違いや誤字脱字などございましたらご連絡いただけますと幸いです！🙏

## 勉強会情報
- 開催日：2020/01/21
- 《 プログラム 》

　16:30 受付開始
　17:00 開場
　17:00 – 17:55 セッション 1 : GKE 入門
　18:00 – 18:55 セッション 2 : Cloud Spanner の技術概要
　19:00 – 19:20 セッション 3 : お客様事例紹介
　19:25 – 20:00 個別相談会 (希望者のみ) 

- 会場：グーグル・クラウド・ジャパン合同会社
〒 106-6126 東京都港区六本木 6-10-1 六本木ヒルズ森タワー
[Google マップで地図を見る](https://goo.gl/maps/iNWVPUNdLbU2) 
- https://events.withgoogle.com/gc-gke-spanner-kiso/


## アジェンダ
- GKE 入門
- Cloud Spanner の技術概要
- お客様事例紹介

# GKE 入門

## スライド
[https://www.slideshare.net/GoogleCloudPlatformJP/gke-spanner-gke](https://www.slideshare.net/GoogleCloudPlatformJP/gke-spanner-gke)

## 内容

### コンテナとKubernetesとは

- コンテナの歴史
    - Googleでは10年以上、検索やGmailなどを無料でユーザーに届けるために、**サーバーリソースを限界まで効率的に使うことができるように**コンテナを使ってきた。
    - 今ではGoogle内では毎週40億以上のコンテナが立ち上がっている
    - コンテナは運用を楽にする。運用チームの人数の増加の10倍の速度でアプリケーションの規模を大きくしてきた。
- コンテナとは？
    - アプリケーショコードとインフラを疎結合にするシステム
    - インフラを抽象化し、アプリケーションから呼び出す部分をラップしているのがContainer Engine
    - VMとは違い、Container EngineがOSとのつなぎこみを行い、GuestOSの部分を立ち上げない分、軽量でポータブルで効率的になる
- **1つのアプリケーションに必要なコンテナを複数まとめてNodeと呼ぶ**
    - 冗長化のために**必要な台数をまとめてClusterと呼ぶ**
        - 複数のNodeにどうやってコンテナをデプロイする？
        - コンテナが何らかの原因で落ちた時に検知や復旧はどうする？
        - 一つ一つリリースしていくの？大変じゃない？
        - コンテナ間の通信はどうするの？
        - => **それらの課題に対応するために Kubernetes を使う**


- Kubernetesの特徴
    - CRD（Custom Resource Definitions）によって拡張性が高い
        - https://qiita.com/cvusk/items/773e222e0971a5391a51
    - 宣言型モデル
        - コンテナの設定ファイルのような何をするのか？をベースにした命令型での設定ではない
        - 何を達成したいのか？を設定ファイルに記載し、その状態を維持するようにKubernetesが持っていってくれる
    - Googleが過去に論文で出したBorgにインスパイアされている
        - https://Kubernetes.io/blog/2015/04/borg-predecessor-to-Kubernetes/

### Kubernetesのアーキテクチャ


- MasterとNode
    - Master側（Kubernetes全体を管理する役割）
        - API Server / Scheduler / Controller / etcd を内包する、Kubernetesの全体管理を担当する
            - etcd => クラスタの全データを格納するデータストア
        - これをどう冗長化するか？が難しい。なのでGKEなどを使うのをおすすめする理由
    - Node側（アプリケーションが動く場所）
        - kubelet / kube-proxy を内包する、Kubernetesのアプリケーションに近い部分を担当する
            - kubelet : Masterとのやり取りを担当するエージェント
            - kube-proxy : IPアドレスのやり取りや、外部Podへのアクセス時のエラー処理などを担当する

### Kubernetesにおける基本リソース（一部）

- Pod
    - 1つ以上のコンテナをまとめた、Kubernetes上で管理する最小の単位
- Deployment
    - Podに対して、新しいアプリケーションのデプロイ・起動しておくPod数の適用などを管轄するためのリソース
    - あるべき状態を実現するためのコントロールを担保する
- Service
    - Podをクラスタの内部/外部に公開するためのリソース
        - アプリケーションのエンドポイントを提供する
            - クラスタ内のIPを提供する
            - L4でロードバランスする場合もここで設定をする
- Ingress
    - L7でロードバランスするためのリソース
    - アプリケーションのエンドポイントを提供する

### Google Kubernetes Engine vs Kubernetes

【GKEを使うメリット】


- GCP上の各サービスとインテグレーション
    - Network service（IngressでのLBやNetwork Routeなどの利用）
    - CI / CD（Cloud build）
    - Logging / Monitoring（StackDriver）
- Master部分はGoogleのSREチームによって管理
    - Masterのバージョン更新をGoogleが管理
        - 今後MasterとNodeのKubernetesのバージョン差異もNode側を自動アップデートすることで対応できるようになる予定
    - etcdの自動バックアップ
- Kubernetesの40%をコントリビュートをしているGKEチームなので、Kubernetesが使いやすい方法（UIや管理方法）を提供しやすい
- Container-Optimized OSを使える
    - ブートが早い
    - コンテナに必要なコンポーネントだけを持つOSなので、セキュリティ的にも安心
    - ※OSSのOS（https://cloud.google.com/container-optimized-os/docs/?hl=ja）


## 質疑応答


- Kubernetesの勉強はどこから始めればいい？
    - GKEから始めるのが良い
    - Codelabで講座があるのでそこから始めてもいいかも（https://codelabs.developers.google.com/codelabs/cloud-gke-workshop-v2/#0）
    - こっちもおすすめ（https://inthecloud.withgoogle.com/gcp-online-handson/gke.html）
- 自動更新ができるらしいけど、すべて下位互換がある？自動更新されるのは実運用だと怖いかも…
    - 自動更新させない設定もできる。
    - アップグレード戦略は色々あるので、そこを参考にすると良さそう（ https://medium.com/google-cloud-jp/gke-upgrade-strategy-8568f450f9d0）
- GKEとAnthosの違いって？
    - GKEはGCP上のもののみのマネージドサービス
    - AnthosはGKE + オンプレのサーバーも合わせて管理できるようにするシステム

# Cloud Spanner の技術概要

## スライド

https://www.slideshare.net/GoogleCloudPlatformJP/gke-spanner-cloud-spanner

## 内容

### Spannerって何？

- NewSQL（Spanner） = RDB（リレーショナル・データベース構造） + NoSQL（水平方向のスケーラビリティ）
    - どちらの要素もいいとこ取りをしたアーキテクチャ
        - YouTubeを扱うのに、MySQLだけでは辛くなったので、Spannerを開発した。
    - メリットのOverView https://cloud.google.com/spanner/?hl=ja#cloud-spanner-
        - Google Adwords / Google Playで 7年以上の運用実績

### 高可用性とその理由


- シングルリージョンであっても、リージョンの中のZoneは複数のZoneに対してレプリケーションされているので、通常のSQL Serverよりも可用性は高い。
    - SLAは99.99%
- マルチリージョン
    - 基本的に3つ以上のリージョンで利用する。
    - Read/Writeができるリージョンが2つ（うち1つがリーダーリージョン、もう1つが役職なしのRead/Writeリージョン）と、ウィットネスリージョン1つの構成で作成する
        - ウィットネスリージョンの役割は、トランザクションのcommitに対しての投票を行う
        - ウィットネスリージョンはReadの役割を持たない
        - https://cloud.google.com/spanner/docs/replication?hl=ja#replica_types
    - SLAは99.9999%
- 1つの大陸構成 / 3つの大陸構成を選択できる
    - https://cloud.google.com/spanner/docs/instances?hl=ja#configs-multi-region
- 3つの大陸構成の場合
    - 上記役割を持つ3つのリージョンの他に読み取り専用リージョンが各大陸に作成される


- 時刻同期（TrueTime API）が使われており、リージョン間でもTimeStampが信頼できるようになるため、ソートの信頼性を持つ。（それによって、下記の**Split**が実現できる => 高いスケーラビリティを実現できる）
    - https://qiita.com/kumagi/items/7dbb0e2a76484f6c522b#truetime-api

### 書き込み時のルール


- Paxosベースのアーキテクチャを使うことで、同期レプリケーションと強い整合性が担保されている。
    - データ書き込み時（commit時）に複数リージョン間でcommit可能か採決を取り、commit実行される
    - 詳細： https://cloud.google.com/spanner/docs/replication?hl=ja#overview_of_replication_in_cloud_spanner

### RDBのシステムとスケーラビリティを実現する Split の仕組み


- Spannerを実現する、Splitの仕組み
    - Splitはデータを格納される単位で、Splitを複数のNode（インスタンス）に分割して置くことで、高いスケーラビリティを実現している
- 基本的に、テーブル内は主キーでソートされている。※Slide 16枚目の図が理解しやすい
    - テーブルはキー範囲で分割される
    - Splitは**負荷とサイズ**に応じて**再度**分割される
        - 負荷とサイズがしきい値を超えると、再度分割され、レプリケートされる
        - 反対に**GCのような形でオプティマイズ**が走り、**負荷とサイズ**が小さければ**結合**もされる
- **TIPS:** SpannerのプライマリキーはUUIDv4を使おう
    - よくある形でTimeStampやAutoIncrementの連番にすると、**すべてのINSERTが一番最後の部分に追記される**ので、（Splitの仕組みで考えると）**特定のサーバーに対して負荷を与え続ける**ことになってしまう
    - => パフォーマンスが1/5（Node数）しか出せなくなってしまう…

### Spanner独特のインターリーブ


- Spannerには外部キー参照はないが、代わりにインターリーブを使うことで同様のことを実現できる
    - インターリーブ（親子関係）
        - データベースの中に複数のテーブルを定義できる（最大7階層まで）
        - データを物理的に**コロケーション**できる
            - インターリーブをすることによって、同じNodeに置くように保証することができる
- **TIPS:** インデックスをインターリーブすることもできる
    - Spannerでは**インデックス自体もテーブル**
    - => インデックスもインターリーブしておかないと、**別のNodeから取得してしまう可能性**があり、パフォーマンスを下げてしまうので注意⚠

### Spannerのトランザクションについて

- トランザクションの種類
    - 読み書きトランザクション
        - 読み取り結果に対して書き込みを行う場合に使うトランザクション。
    - 読み取り専用トランザクション
        - 複数のテーブルなどから一貫してデータを取得する時に使うトランザクション
        - ロックは発生しない
- トランザクションの処理とロックの種類
    - データ読み取りをせずに書き込むトランザクション（ブラインドインサート）
            - ライター共有的ロックと呼ばれる共有的ロックを用いる
            - コミットタイムスタンプの順に順序が決定される
    - 読み書きトランザクション
        - データを**読み取るタイミングでは共有的ロック**、**書き込むタイミングで排他的ロックを取得**して書き込みを行う
    - **Spannerの特殊な読み取りトランザクション**
        - Strong Read
            - 最新のデータを読み取る（一般的なDBはこうで、デフォルト設定もこれ）
        - Steal Read
            - タイムスタンプ指定をすることで、過去のデータを読み取れる読み取りの方法
                - Strong Readの場合、最新版のデータを取得しに行くためにリージョン横断が起きるので、レイテンシが発生するが、Steal Readではローカルリージョンのデータを取得するのでレイテンシを防ぐことができる
                - ただし、古いデータでも許容できる内容でないと問題が起きる可能性はある
            - トランザクションのロックはかからない
- トランザクション実行時には
- **TIPS:** **トランザクションは、レコードではなくセルだけをロックする**

### Spannerにおけるデータ書き込みの方法

- DML
- Mutation API
    - insert_or_updateなどのMutetionにしか無いAPIがある
    - 若干こちらのほうがパフォーマンスが良い（ローカルでバッファリングを行っているため）
- 注意事項：同じトランザクションに対してDML / Mutation APIをどちらも使うのはやめたほうが良い。処理の実行タイミングが異なっていて、DMLが先に実行されるため。

**その他デモ内でのTIPS**

- 負荷状況やSlow Queryはコンソールから確認できる
    - Monitoring: QPSやCPU使用率
    - Query Stats: 遅いクエリーの情報を確認できる
- Spanner自体、空の状態から数件追加された段階ではSplitを使用していない
    - => Warmupしないで使うと、すべてのノードを使われずパフォーマンスが上がっていないのでスピードが落ちてしまう
    - => ダミーデータを入れて、そのデータを消すことで、Warmupを実施できる。Splitはすぐに消されないので。
- インスタンスのNode数の上げ下げはダウンタイムなしで実行できる


## 質疑応答

- splitは結合される？
    - オプティマイズする仕組みがあるので、それによってマージはされる
- 金額が高いが、どれぐらいの規模から利用すべき？
    - **TCOを考えないといけない（落ちたときの機会損失や負荷への対応コスト）**
    - 1 Node（月7万円）。見えないコストも含めて計算した時にこれよりも小さいのであればSpannerじゃなくても良いと思う
    - 1 Nodeでも可用性が非常に高いので、SpannerのほうがRDB（Cloud SQL）を使うよりも安心なことも往々にしてある


# お客様事例紹介


- **コロプラ**
    - **DQウォークでの構成**
        - ユーザー系DBはすべてCloud Spanner
        - 10,000+ Pods on GKE
- フルクル（初めてのCloud Spanner国内導入事例）
- メルペイ（金融系事例）