SpannerをRESTでつかってみた
2017-08-30 ExistMikan
自己紹介
@ExistMikan ・会津大学卒 (2012年)
→ IT系の猛者が集う大学
・上記大学発ベンチャー企業に就職
→ スマートフォンアプリ(Android/iOS)の開発に従事
・現職場(吉積情報株式会社)に転職 (今年)
→ GCP中心の開発へ
・先週、パパエンジニアと化す
寝不足多幸感 VS
大分前から放置気味の
アカウント(´・ω・`)
SpannerをRESTでつかってみた ざっくり目次
・spannerの話
・RESTの話
・セッションのキャッシュの話
・ベストプラクティスの話
・検証してみた話
Spannerとは?
水平スケーリング可能でグローバルな整合性を備えた、
初のリレーショナル・データベース
提供状況
・2017/02/14 ベータ発表
・2017/05/16 GA
・2017/06/16 東京リージョン選択可
こりゃ使うしかな
い!
大まかな構造
インスタンス
データベース
テーブル
インデックス
インスタンスの下に、各種構成要素がぶら下がる形。
インスタンスはノード数を設定でき、この数が性能と料金に直結する。
Spanner Consoleで出来ること
・インスタンスの作成 /削除
・データベースの作成 /削除
・テーブルの作成/削除
・インデックスの作成 /削除
・クエリ
出来無さそうなこと。。。
・データの追加/削除
→ クエリ入力欄にINSERT文を入れても反応せず。。
インスタンスの設定
asia-northeast1だけ割高
ノード数を上げると、性能が向上。
これがスケールアウトに相当。
現在は手動切替のみ。
ベストプラクティスが
重要になってくる
ここに指定したインスタンス IDが、
そのままREST APIのパスとして使われていきます。
例:"projects/<projectId>/instances/<instanceId>/databases/<databaseName>
他のリージョン
データベース/テーブル/インデックスの作成
データベース
データベース名を決めるだけ
テーブル インデックス
テーブルもインデックスも UIで作成可能
DDLの使用
スキーマ定義用のテキストで作成することも可能
クエリ
クエリもサクッとコンソールから実行可能
RESTでアクセス!
なぜREST?
→ GAE + SE(Java)の環境で、DBをDataStoreからSpannerに切り替えたくなった
→ しかし、GAE + SEではgRPC系ライブラリが提供されていない
→ RESTでやるしかない
GoではGAE + SEでもライブラリが
動作するらしい。。
Goのライブラリでは
Socket APIを裏で使っているため、
OverQuotaに注意
つらい
RESTでやる場合はURL Fetchの
OverQuotaに注意。
RESTライブラリ for JAVA
Cloud Spanner API Client Library
https://developers.google.com/api-client-library/java/apis/spanner/v1?hl=ja
RESTをラッパしたいつもの Googleライブラリは提供されている
Eclipseでの導入方法 (プロジェクトを右クリック →Google→Google APIの追加)
※Google Plugin for Eclipseの場合。Cloud Tool for Eclipseのパターンは未検証。。。
REST APIの一覧
認証周り
インスタンスの情報
インスタンスの管理
データベースの管理
データベースオペレーションの管理
セッションが絡む処理
(セッションの作成/削除、データの作成 /更新/削除、クエリ)
インスタンスオペレーションの管理
SpannerAPIの利用方法
・認証
・インスタンス/データベース/テーブル/イ
ンデックスのAPIを実行
・時間がかかるものはオペレーション API
をポーリングして状況把握
管理系 データ操作系
・認証
・操作するデータが入っているデータベー
スのセッションを取得
・セッションAPIにて、
データの操作を行う
・取得したセッションを削除する
(必要であれば)
GAEの1リクエストの中で、下記のような流れで APIを叩いていく
認証
SpannerのAPIにアクセスするためのオブジェクトを下記の様に生成
認証に関係するHttpRequestInitializerの生成コードは下記
デプロイ環境でのアクセスはAppIdentityCredentialにスコープを設定するだけでOK
ローカルとかで触りたい場合は認証用のキーを入手しておき、それを指定して作成
インスタンスを作成する:REST API リファレンス
REST APIのリファレンス
GCP ProjectのIDが入る
インスタンスを作成する:APIライブラリ
APIのパラメータを作成する部分
APIを実行する部分
長時間実行オペレーションの管理
オペレーション名をパスに含め、
オペレーションのステータスを
問い合わせるAPI。
instance用とdatabase用でクラスが
違うので注意(パスが異なるため。
スーパークラスは同じ )
ポーリングしてオペレーションの状態を確認できる API
データベース/テーブル/インデックスの作成
※やり方はインスタンスと同様の手順につき割愛
セッションの生成
セッションを作成したいデータベースまでのパス +”/sessions”となるパスに対してPOST (パラメータは空)
SessionオブジェクトのgetName()で取得できる文字列がセッション。
データの書き込み
commitというAPIがあり、それに更新内容を詰めてPOSTする形。パスの殆どはセッションで、下記のような文字列になる。
projects/project-amaterasu/instances/main-instance/databases/main-db/sessions/AO6KeAX4B5A0hUz3_d1bjBQ0T8wrsxNqS-lbplIDWcM8_X727kVAlK9Fm40
変更内容のオブジェクト
トランザクションの指定
データの書き込み
ライブラリ側は対応するオブジェクトを下記のように作り込む形となる。
下記は単一の行を単純に書き込む例。
writeXXXX(Object, xxx)は適切に
キャストするための即席関数
データの書き込み:即席関数
Spannerが認識する型のオブジェクトに適宜変換。
INT64にはIntegerでは入れられないなどがあった。
(実質Longだから? しかしLongも文字列..)
データの書き込み:プチハマりポイント
タイムスタンプ型は日付フォーマットの文字列指定する
→ ドキュメントにはタイムゾーン設定などができそうな形だったが、
実際はオフセットなし、 UTC固定のRFC3339文字列しか入らなかった
何故
データの読み込み
データ操作系なので書き込みなどと同様、セッションが必要。
SQL文字列を指定する。
‘@’パラメータによるプレースホルダー指定も可能(大事)
データの読み込み
実行結果からgetRows()でオブジェクトのリスト、のリストを取得。入れた順に入っているので都度
キャストしながら取得。※以下サンプルはplaceholder無し版
データの読み込み:即席関数
書き込みのときと同じノリで変換。
データの読み込み:プチハマリポイント
概ね”yyyy-MM-dd’T’HH:mm:ss.SSS’Z’でくるのだが、ミリ秒以下がちょうど 0だと、
ピリオド以下がばっかり切られる
→上記フォーマットだとパース失敗 (´・ω・`)
→暫定対処で対応した。。
データの削除
データ書き込みのときの commit APIを利用するが、Mutationの中身をinsertOrUpdate
等ではなく、deleteを使用する。(サンプルコード省略)
セッション管理
読み書きするために必ず必要になる、Cloud Spanner データベース サービスとの通信チャネル。
Client Libraryには、Channnelという概念があり、そこでセッションプールのような管理がされているようだが
RESTでは該当する概念無し。
生成のためのレイテンシがそれなりにかかる(100ms~1000msくらい?)
→ リクエストするたびに生成/削除をやるのはコストが高い
毎回やりたくな
い!
そうだ、
キャッシュしよう
セッション管理
1個のセッションを全てのリクエストで使いまわして負荷を掛けてみた
秒間100リクエストくらいの書き込みまでは 200ms程度で捌けたっぽい
秒間300リクエストくらいになってくると、 10秒以上のレイテンシが発生するように。
完全にアウト
検証用のフロントエンドインスタンスも爆速で増加(´・ω・`)
良い子はまねしてはいけない
セッション管理:キャッシュ
セッションの各種制限
使ってなければ勝手に消してくれる
削除
トランザクションとの関係
キャッシュする場所はどこ?
・インスタンス毎にメモリに持つ
・Memcache/DataStoreに入れる
readでもwriteでもトランザクションは貼られる。読み書きはロックするが、読み取り専用はロックしない。
セッション管理:キャッシュ場所
・簡単そうだが、インスタンス間で共有できない
→ インスタンス数の増加によっては、
セッション数の上限に達してしまうのでは?
→ コワイ
インスタンス
セッション
セッション
セッション
インスタンス
セッション
セッション
セッション
・インスタンス毎にメモリに持つ
・Memcache/DataStoreに入れる
インスタンス
セッション
セッション
インスタンス
セッション
セッション
・全インスタンス間で共有できる
・状態をもたせるのはつらそう(atomicに更新が厳しい)
・max値を決めておけば、上限を超えることはない
→ 負荷が高まった時は、1つのセッションを同時に使うリクエストが増える
→ 読み込みは快速だが、書き込みが1つのセッションに集中するとロックがかかるの
でその分遅くなる
・併用しているのは毎回DataStoreにreadしにいくとread entitiy分の料金が発生する
ため。
管理しやすそう
セッション管理:フローチャート
ランダムなキーでセッションを取って、なければ作り、あればそのまま利用する形で Try
(簡単化のため毎回セッション有効判定を実施 )
多量のリクエストを捌けた (・∇・)
ベストプラクティスとホットスポット
Spannerには、パフォーマンスを最大化するために、スキーマの設計などに関してベストプラクティスがある。
ベストプラクティスとは?
主キーの選択
→ 値が単調に増加する列を最初のキー部分に選択すると、キー空間の最後にすべての挿入が実行されるため、
誤ってホットスポットが作成される可能性がある
Cloud Spanner は分散データベースなので、データベースが
大きくなると、Cloud Spanner は「スプリット」と呼ばれる塊に
データを分割します。各スプリットは、相互に独立して移動で
き、異なるサーバーに割り当てることができます。サーバーは異
なる物理的なロケーションに存在することもあります。
連続しているデータは別のスプリットに分割されにくい
挿入が同じスプリット =同じDBになるので、負荷が集中する
ホットスポットの影響(イメージ)
ノードA
ノードB
ノードC
スプリットA
スプリットB
スプリットC
スプリットD
ID:111112
ID:111111
ID:111110
ID:111109
:
ID:2222
ID:2221
ID:2220
ID:333
ID:332
ID:331
ID:9
ID:8
ID:7
・単調増加だと、赤字の行が追加される時は一番上のスプリットにアクセスが発生する。
・近いKeyの範囲でスプリットは作られるため、単調増加の際は必ずスプリット Aを管理するノードAにアクセスが
かかる
・ノードB、ノードCをフル活用できていないので、ノード数を追加しても性能向上の恩恵が受けられない
脱ホットスポット
ノードA
ノードB
ノードC
スプリットB
スプリットC
スプリットD
ID:ohwoehlife
ID:ohwoexlife
ID:ohwoedlife
ID:ohwoeflife
ID:bfewpof
ID:bfewpeg
ID:bfewpwg
ID:bfewpdg
ID:xpihufnew
ID:xpihufnv
ID:pdihufnoew
ID:brejefiewi
・keyがuuidのような形だと、新規追加の場合であっても、追加されるのはその keyと近い範囲のスプリット
・スプリットが別になるので、管理しているノードへの負荷も分散される
スプリットA
・タイムスタンプをキーにしたテーブルと、UUIDをキーにしたテーブルを用意し、負荷を掛けて比較
・ノード数1の場合と、ノード数3の場合で検証する
・GCEから秒間リクエスト500になるように、GAEにデプロイしたAPIを叩く → 30分継続実行
・APIでは、リクエストを受けたら新しい行をテーブルに追加するREST APIを実行する
・30分の実施後、DBは一回DB毎削除する→世代管理されているので中身をカラにするだけではダメ
ホットスポット検証
ちゃんと分散されるほう ベストプラクティスに沿わないヤツ
SimpleTable
TimestampTable
25.11%
26.45%
ノード数1では対してCPU使用率に変化なし。全スプリットを 1ノードで管理するためと思われる。
ノード数1
SimpleTable
TimestampTable
・ノード数3にしたことで、CPU使用率がきっちり下がっている
・タイムスタンプをキーにしているテーブルは、 UUIDをキーにしているテーブルより CPUを喰っている!
8.728%
12.49%
ノード数3
検証まとめ
・高い処理効率を維持するには、ベストプラクティス準拠 & ノード数を3以上にするのが良い
→ キー選択以外にも多くのベストプラクティスがある
→ 想定リクエスト数で、 CPU使用率が75%を下回っているなら、ノード数は 1でも問題にはならない
超実践 Cloud Spanner 設計講座
https://www.slideshare.net/HammoudiSamir/cloud-spanner-78081604
Spannerユーザ必読。ノードやスプリットの関係についても言及されています。
普通のエンジニアが【Cloud Spanner】使ってみた
https://www.slideshare.net/ssuserc49633/20170822-cloud-spanner
こちらも参考情報盛りだくさんです。
参考資料
吉積情報とクラウドエースでは、
一緒に働いてくれる社員を募集しています!
Spanner使い放題!!
多分!
JOINした暁には・・・

Spannerをrestでつかってみた