超実践 cloud spanner 設計講座
Post on 21-Jan-2018
6.175 Views
Preview:
TRANSCRIPT
超実践 Cloud Spanner 設計講座知ってることを全て紹介します!
Proprietary
Samir Hammoudi aka サミールクラウドカスタマエンジニア
JULY 21, 2017
Cloud Spanner とは?
Google のマネージド・スケーラブル・リレーショナルデータベース・サービス
完全マネージドのグローバルスケールで DB サービス1
2
3
4
ゾーン間・リージョン間の自動 synchronous レプリケーション
スキーマ、ACID トランザクション、SQL
Google内部では、既に5年以上の運用経験(AdWords, Google Play…)
注意事項:Cloud Spanner ≠ MySQL
Cloud Spanner は MySQL の単なる置き換えではない
● スキーマは似てるが、分散データベースのため、MySQLと違う可能性がある
● SQL の SELECT系とDDLは対応済み、DML も対応予定
→ 現時点では Mutation オブジェクトを利用して INSERT/UPDATE/DELETE を行う
● Auto-increment がない(Spannerではアンチパターンだから)
● MySQL 互換ではない(Spannerのクライアントライブラリを提供)
● パフォーマンスのプロファイルが違う(Scale-up DB vs Scale-out DB)→ 高負荷をかけても Cloud Spanner のレイテンシは安定(Quizletの事例をご参考ください)
● Cloud Spanner では PK の選択がクリティカル ←これ何回言っても足りないので赤にしました!
● FK が存在しない(Spanner では Interleave が FK 相当)
MySQL とは似てるところも色々あるが、Cloud Spanner は分散データベースだということを忘れないでね!!
MySQL ではないが...
特に大規模アクセスのあるコンテンツやDB運用に苦労しているサービスに最適!
ノードを追加するだけでオートシャードされ、理論上無限にスケールしつつ、
レイテンシーがより安定 :)運用も楽 ^_^
今日のおさらいリスト
1. PK の選択が重要 ←これが1番重要!!
2. なぜテーブルをインターリーブするか?
3. インデックスとインターリーブについて
4. Channels と Sessions5. ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか?
6. エラーについて
7. 容量に関する上限 8. テーブルが分割(Split)されるロジック
9. 負荷試験は十分長く実行する
10. 負荷試験間はデータベースをDropする
11. TPSの数え方
12. ノード数を縮小するについて
13. グラフの ”Total storage” の意味って?
14. Query Plan Cache ←これも重要!!
PK の選択が重要
● シーケンシャルな PK を使わないこと → hotspots が発生する
○ auto-increment PK を使わない (even though it doesn’t exist in Cloud Spanner!)○ 時系列の PK を使わない
● MySQL の auto-increment を使用しているテーブルを Spanner にインポートする場合は:
○ 新しい PK を作り、乱数をオススメします (e.g. UUID).○ 元の PK から 計算する shard_id を作る (e.g. shard_id = hash(auto-inc_id)).○ シーケンシャルな PK を使うが、DB に格納する前やクエリーする時はビットを逆にする
● UUID が一番おすすめとしている PK です。
これ重要!
PKを選択する時の注意点 - Hotspot (1/2)
● Hotspot とは、データが Spanner サーバー間にちゃんと分散されない現象
○ 1つの Spanner サーバーに書き込みが集中して、パフォーマンスが減少
○ 同じサーバーを利用するサービスにインパクトも可能
● 現象の理由
○ 新しく書き込まれるレコードはテーブルの最後に追加されて、同じ Spanner サーバーに格納
される(時系列のPK)
CREATE TABLE Users ( LastAccessTimestamp INT64 NOT NULL, UserId INT64 NOT NULL, ...) PRIMARY KEY (LastAccessTimestamp, UserId);
PKを選択する時の注意点 - Hotspot (2/2)
● Hotspot の対策
○ PK の順序を交換
○ 新しく書き込まれるレコードは、テーブルの最後に追加されず、 Spanner サーバー間にちゃんと分散される
CREATE TABLE Users ( UserId INT64 NOT NULL, LastAccessTimestamp INT64 NOT NULL, ...) PRIMARY KEY (UserId, LastAccessTimestamp);
なぜテーブルをインターリーブするか
user_id
SELECT user_name, item_id FROM users INNER JOIN items ON users.user_id = items.user_id WHERE user_id = 1234;
user_id user_name
1111 john
1122 paul
1234 bob
user_id item_id
1111 001
1111 002
1234 001
user_name
user_id
item_id
1111 john
1122 paul
1234 bob
1111 001
1111 002
1234 001
Spanserver A Spanserver B1111 john
1111 001
1111 002
1122 paul
1234 bob
1234 001
Spanserver A
Logical View Physical ViewNo interleave
Physical ViewWith interleave
インタリーブをすると、 JOIN クエリが2つのサーバにアクセスすることもなく、1サーバで済む
インデックスとインターリーブについて
テーブルがインターリーブされている場合、不要なインデックスを作っているかもしれません。
See the example below:
Table DDL index
user
CREATE TABLE test_user (user_id INT64 NOT NULL,create_date TIMESTAMP NOT NULL) PRIMARY KEY (user_id)
CREATE INDEX idx_user_idON user (user_id)
item
CREATE TABLE test_item (user_id INT64 NOT NULL,item_id INT64 NOT NULL) PRIMARY KEY (user_id, item_id),INTERLEAVE IN PARENT user ON DELETE CASCADE
CREATE INDEX idx_user_id_in_itemON item (user_id)
この例ではセカンダリインデックスは不要です
PK は自動的に インデックスされる
user_id は既に親テーブルでインデックスされている
Channels と sessions
● Channels○ Cloud Spanner へ接続する gRPC コネクション数
○ Default = 4, max = 256.○ コードの中で定義する必要がある
■ SpannerOptions options = SpannerOptions.newBuilder().setNumChannels(8).build();
● Sessions○ Session はトランザクションを実行できるコンテキストです。並列で行われるトランザクションは各自 session
を利用する必要がある。例えば、あるアプリが並列に100トランザクションを行うとしたら、Session pool を最
低100に設定する必要があります。
○ Default value = Default number of channels * 100 = 400○ Recommendations: Number of sessions = number of expected threads○ データベースごとにセッション数の上限が:10000 per node.○ 詳細はこちら:https://cloud.google.com/spanner/docs/sessions?hl=ja
エラー (auto-retry or SpannerException)
Cloud Console 上のグラフにエラーが発生する場合
があります。
● エラーの原因は通常トランザクションが abort されたからです
● エラーが発生したとグラフで見えるが、コード
の中で SpannerException をキャッチできな
い
● それはクライアントライブラリが自動的に abort されたトランザクションをリトライするか
らです
● 自動リトライが失敗すると、 SpannerException をキャッチできます
● 基本エラーは無視しても問題ありません
ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか? (1/5)
S S S S ノード = Spanner Servers2TB まで管理できるサーバ
Colossus (分散ストレージ )実データはここに格納される
C クライアント
Split
ノード数:4
各ノードは 複数の Split のオーナー
ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか? (2/5)
S S S S ノード = Spanner Servers
Colossus (分散ストレージ )
C クライアント
Split
ノード数:4>3
1ノードを削除
ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか? (3/5)
S S S ノード = Spanner Servers
Colossus (分散ストレージ )
C クライアント
Split
ノード数:31〜2秒後
Split のオーナーが変わるだけ
ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか? (4/5)
S S S S ノード = Spanner Servers
Colossus (分散ストレージ )
C クライアント
Split
ノード数:3>4
1ノードを追加
ノード追加・削除の際、リシャードがなぜ1〜2sでできるのか? (5/5)
S S S S ノード = Spanner Servers
Colossus (分散ストレージ )
C クライアント
Split
ノード数:41〜2秒後
Split のオーナーがまた変わるだけ
容量に関する上限(2GB and 2TB)
Cloud Spanner には 2TB size limit per node という容量上限があります。
インターリーブテーブルを使うと、裏上限がもう1つあります: 2GB per parent record and related child records
Max 2GB
テーブルが分割(Split)されるロジック
Cloud Spanner は容量と負荷状況次第、テーブルを split します。ただし、実際にどのタイミングでテーブルが分割されるか
は保証できません。
Cloud Spanner では以下の2つの条件でテーブルが分割されます:
● Size-based splits○ テーブルの容量が数GB程度になったら、テーブルを split します
● Load-based splits○ Cloud Spanner は分散できる負荷だと、テーブルを split します。分散できない負荷は、 例えばシー
ケンシャルな INSERT(だから Hotspot が発生する)。
上記は、どれだけ PK の選択肢が重要かを示しています。
負荷試験は十分長く実行する
Cloud Spanner の負荷試験を行う場合、5分ではなく、20〜30分の負荷試験をオススメします。その理由は、データの容量
が多くなることにより、Split がより多く発生して、データが正常に全ノード間に分散されるからです。
テーブルが十分 split されると、全ノードが
活用され、Cloud Spanner の最大の
パフォーマンスを出せるようになります。
Split happens
負荷試験間はデータベースをDropする
負荷試験を毎回行う際は、Insert したデータを全て削除するのではなく、データベースを Drop するようオススメします。
データの削除+再Insert は、テーブルスキャンのパフォーマンスを劣化します。それは、削除されたデータは Garbage Collector が物理的に削除するまではテーブルに append されるからです。テーブルのクリーンアップまで1週間までかかり
ます。
Spanner のストレージは log-structured merge trees (LSM Tree)を使用している。 → Delete のオペレーションは "append a delete mutation" とストレージレベルで見られる。古いデータはデータベースがク
リーンアップされるまで削除されない。
→ 削除された PK がまだ格納されているので、テーブルスキャンがインパクトされる。
TPSの数え方
パフォーマンスグラフは受信した API リクエスト数を表示する
● "reads/s" は read と query を含む
● "writes/s" はトランザクションのコミット数を示す その結果、TPS は "writes/s" ということになります 3 read API calls と 9 buffered mutations を含むトランザクションは 3R, 1W とカウントされる
ノード数を縮小するについて
Cloud Spanner にはオートスケール機能はまだありません。
ノード数を縮小しようとすると、1ノードまでに縮小できない場合があります。
Spanner の仕組み上、Delete や Update されたデータは Garbage Collector が起動するまでに一時的に格納されます。そ
の理由は2つ:整合性のあるバックアップを行うためとより高いパフォーマンスを提供するためです(Cloud Spanner はデー
タ容量が多いほど、パフォーマンスが出るので)。
1
2
3
1. Monitor Spanner CPU usage
2. Trigger function when threshold hit
3. Function add a node
Autoscale workaround
グラフの ”Total storage” の意味って?
Cloud Console のグラフとして表示される “Total storage” には最新のデータ+
削除・更新されたデータを含まれています。削除・更新されたデータは1週間以内
にクリーンアップされます(平均 3.5 日)。
古いデータを一時的に確保するメリットは:● 高スループットの Read/Write を提供するため
● 整合性のあるバックアップを取るため
お客様に課金されるデータ:
● ライブデータ
● 削除・更新されたデータ(1週間以内にクリーンアップされるまで)
Query Plan Cache
SQL クエリを Spanner で使用する際に、bound parameters を使用す
るのが重要です。
Cloud Spanner のノードは query plan cache の数が限られています。
クエリの中に静的パラメータを使用すると、各クエリが違うものと見られ
て、query plan cache を効果的に活用することができません。この問題
を避けるには、以下の例のようにクエリは parameter binding を利用す
る必要があります。
Statement statement = Statement .newBuilder("SELECT name WHERE id > @msg_id AND id < @msg_id + 100") .bind("msg_id").to(500) .build();
これ重要!
Additional readings
● SQL Best Practices● Best Practices for Schema Design● Efficient Bulk Loading● Quizlet Cloud Spanner tests
top related