Kekeの日記

エンジニア、読書なんでも

データベースクラスタリングシステムVitess

https://i.ytimg.com/vi/q65TleTn2vg/maxresdefault.jpg

本記事

本記事ではKubenetes上にデータベースクラスタリングシステムの入門として導入して、使い勝手や操作方法、運用方法などの学習します。

目次

Vitessについて

Vitessとは

f:id:bobchan1915:20181007205913p:plain

VitessとはMySQLの水平方向スケールアウトを提供するためのデータベースクラスタリングシステム

Youtubeで2011年から使われていたそうです。

特徴

以下のような特徴があります。

1. スケーラビリティ

一般的にはRDBはスケールするのが難しいという印象でしょう。

f:id:bobchan1915:20181008025538p:plain

特にMySQLはReplicaを置くことができますが、それでもスケール性は高いとは言えません。

しかし、NoSQLのようにすると以下のようにシャーディングすることができます。

f:id:bobchan1915:20181008025648p:plain

しかしVitessを使うことによってNoSQLのようなスケール性を提供します。

これはシャーディングをしているからです。

2. ハイパフォーマンス

Vitessはデータベースパフォーマンスを悪くするクエリを自動で書き換えて効率よくします。

キャッシングや中間クエリを使って重複したクエリが実行されないように自然に置き換えます。

3. マネジメントのしやすさ

Vitessはマスターフェイルオーバーやバックアップというものを自動的に行ってくれます。。

ロックサーバーを使って管理者サーバーを監視して、データベースのトポロジーを意識せずに済む様にします。

4. コネクションプール

MySQLの接続にかかる多大なメモリオーバーヘッドを削減します。gRPCベースのプロトコルは一度に1000以上の接続でも捌けます。

クライアントからもgRPCで接続します。

f:id:bobchan1915:20181008025835p:plain

5. シャードマネジメント

MySQLは本来はシャーディングはサポートしていないが、データベースに対して必要になるときがくるかもしれない。 それをバックエンドで自動でやってくれるので、何もアプリケーションは書く必要がなくなる。

6. ワークフロー

クラスタについてメタデータを常に追跡し続けるのでクラスタ監視は常に最新な状態に保つことができます。

大事なコンセプト

1. Keyspace

論理データベースである。シャードをしていなければMySQLの名前で直接マッピングされます。

シャードされていたら、keyspaceはいくつものMySQLデータベースにマッピングされるが、一つのデータベースにアクセスしているようにみえる。

2. Cell

セルとは特定の範囲で物理的に独立した配置されたサーバとネットワークインフラのグループです。

それぞれのセルはlocal topology serviceがあって、セルの中にホスティングされます。

Vitness tabletsの情報を格納しています。

3. Topology Service

バックエンドで走っている処理をこと。 それぞれはトポロジーデータと分散ロッキングシステムを提供している。

VitnessはKubernetes上だとetcdを使っていてKey-Value形式になっています。

4. Tablet

mysqldとvttabletプロセスのコンビです。

5. Shard

Keyspaceを分割したもので、MySQLマスターとスレーブから構成されます。

アーキテクチャ

以下のようなアーキテクチャです。

https://raw.githubusercontent.com/vitessio/vitess/master/doc/VitessOverview.png

大きくruntimeadminに分かれていてadminに関するところが私たちの部分です。

一方でruntimeはデプロイしているアプリケーション側の話です。

ここで役割について解説します。

もしかしたら特にvttabletなどはこっちの図の方がみやすいかもしれません。

f:id:bobchan1915:20181008023545p:plain

1. Topology

Topology Serviceはメタデータを格納して動作しているサーバーの情報を持ち、シャーディングのスキーマなりを保持しています。バックエンドにはデータストアがあり、vtctlCLIツールとvtctldというWebインターフェースからアクセスすることができる。

Kubernetesではdata storeにはetcdが使われています。

これには二つのインスタンスの種類があります。

1.1 Global vs Local

クローバルインスタンスとPer-cell Localインスタンスがある。

  • Globalインスタンスはあまり変わらないトポロジーのグローバルなデータを格納しています。例えばKeyspaceやシャードについてです。
  • セル一つにつき、一つのローカルインスタンスがあり、セルの設定情報を保持している。また、またrolled-upデータを持っていて、クライアントがデータを探しやすいようにする。

Globalインスタンスが停止してもあまり影響はないが、Localインスタンスが停止すると、そのセルは使わない方がいいです。

Vitnessはクエリを処理するのにTopologyを使うことはなく、起動時やバックグラウンドでTopologyさーばーにアクセスしてTopologyの情報を得ている。

1.2 スキーマ管理

Vitnessでは二つのスキーマがあります。

  • MySQLスキーマ: それぞれのMySQLスキーマです
  • VSchema: keyspaceとどのようにシャーディングされるかを指定します

シャーディングとは何かというと以下のようにシャードキーによって水平分散をすることです。

f:id:bobchan1915:20181008025500p:plain

引用

gihyo.jp

2. vtgate

vtgateは軽量なプロキシサーバーで、正しいvttabletにトラフィックをルーティングする役割を持つ。

また、それぞれの結果に対して合算した結果を返します。

クライアントはvtgateさえ見つけられればクエリを投げることができます。

また、ここがシャーディングスキーマなりレイテンシ、tabletsの稼働状況などを持っています。

3. vttablet

vttabletはMySQLのプロキシサーバーである。SidecarのようにそれぞれのMySQLインスタンスの前に存在する。

役割としては、vttabletはスループットを最大化するようにして、MySQLをひどいクエリから守ります。

コネクションプーリング、クエリ書き換え、クエリのキャッシュの機能もある。

これを挟むことによってMySQLドライバではなくて、Vitessクライアントを使うようになる。

4. vtctld

これはWebインターフェース用のサーバーである。

Kubernetesにホストする

リポジトリを取得する

go get vitess.io/vitess/go/cmd/vtctlclient

クラスタを作成する

以下の様にしてクラスタを作成してください。

gcloud container clusters create vitness-example --zone=$(gcloud config get-value compute/zone) --scopes storage-rw

あとあとわかったのですが、--machine-type=n1-standard-4以上にしないとCPU不足になり起動できませんので注意してください。**

ここでCloud Storageのスコープを付与しています。

バックアップ用のCloud Storageバケットを作成する

以下のように作成します。あまりアクセスしないので安いnearlineにしています。

gsutil mb nearline  gs://vitess-backup-tutorial

設定ファイルconfig.shを作成

以下のように実行します。

./configure.sh

Vitess Docker image (leave empty for default) []:
Backup Storage (file, gcs) [gcs]:
Google Cloud Storage bucket for Vitess backups: vitess-backup-tutorial

NOTE: If you haven't already created this bucket, you can do so by running:
      gsutil mb gs://vitess-backup-tutorial

etcd-operatorを作成

etcd-operatorはKubernetes上でのetcdクラスタを管理します。

helm install stable/etcd-operator --name etcd-operator

以下の様に確認できます。

kubectl get pods

NAME                                                              READY     STATUS    RESTARTS   AGE
etcd-operator-etcd-operator-etcd-backup-operator-6b697d96cxxvb4   1/1       Running   0          44s
etcd-operator-etcd-operator-etcd-operator-676764c476-24spd        1/1       Running   0          44s
etcd-operator-etcd-operator-etcd-restore-operator-7c8d68792nmhg   1/1       Running   0          44s

Topologyの起動

以下のようにクラスタの全てのデータをKey-Valueで持っているTopologyのためのetcdを起動します。

./etcd-up.sh

Creating etcd service for 'global' cell...
etcdcluster.etcd.database.coreos.com/etcd-global created
Creating etcd service for 'test' cell...
etcdcluster.etcd.database.coreos.com/etcd-test created

すると以下のようになっています。

kubectl get pods

etcd-global-794b9g2rjd                                            1/1       Running   0          10s
etcd-global-swrt75dz5z                                            1/1       Running   0          34s
etcd-global-tvz66j5vdp                                            1/1       Running   0          51s
etcd-operator-etcd-operator-etcd-backup-operator-6b697d96cxxvb4   1/1       Running   0          2m
etcd-operator-etcd-operator-etcd-operator-676764c476-24spd        1/1       Running   0          2m
etcd-operator-etcd-operator-etcd-restore-operator-7c8d68792nmhg   1/1       Running   0          2m
etcd-test-4qw4zhcqgk                                              1/1       Running   0          51s
etcd-test-g2rrqck4lw                                              1/1       Running   0          34s
etcd-test-vflnqk9n2x                                              1/1       Running   0          10s

vtcdldを起動

以下のようにしてvtcdldを起動します。

./vtctld-up.sh

Creating vtctld ClusterIP service...
service/vtctld created
Creating vtctld replicationcontroller...
replicationcontroller/vtctld created

To access vtctld web UI, start kubectl proxy in another terminal:
  kubectl proxy --port=8001
Then visit http://localhost:8001/api/v1/namespaces/default/services/vtctld:web/proxy

同じく確認すると以下のようになっています。

kubectl get pods

NAME                                                              READY     STATUS              RESTARTS   AGE
etcd-global-794b9g2rjd                                            1/1       Running             0          1m
etcd-global-swrt75dz5z                                            1/1       Running             0          1m
etcd-global-tvz66j5vdp                                            1/1       Running             0          1m
etcd-operator-etcd-operator-etcd-backup-operator-6b697d96cxxvb4   1/1       Running             0          3m
etcd-operator-etcd-operator-etcd-operator-676764c476-24spd        1/1       Running             0          3m
etcd-operator-etcd-operator-etcd-restore-operator-7c8d68792nmhg   1/1       Running             0          3m
etcd-test-4qw4zhcqgk                                              1/1       Running             0          1m
etcd-test-g2rrqck4lw                                              1/1       Running             0          1m
etcd-test-vflnqk9n2x                                              1/1       Running             0          1m
vtctld-p8n9p                                                      0/1       ContainerCreating   0          27s

ポート転送をしてGUIを確認

以下のようにしてポート転送をします。

そして以下のURLにアクセスして確認してみます。

kubectl proxy --port=8001

port-forwardでもいけます。

kubectl port-forward vtctld-p8n9p 8001:15000

この違いは

kubectl proxy --port=8001

は汎用亭であるがゆえに、コンテナへのアクセスは

http:localhost:[PORT]/api/v1/proxy/namespaces/[ネームスペース]/services/[サービス名:コンテナのPort(ここではweb=15000である)/

であるのに対してkubectl port-forward特定のPodへのポート転送なので

http://localhost:[PORT]

でアクセスできる違いがある。

ともあれ以下のURLにアクセスします。

http://localhost:8001/api/v1/proxy/namespaces/default/services/vtctld:web/

すると以下のような画面がみられるはずです。

f:id:bobchan1915:20181008053848p:plain

gRPCでクライアントにアクセスする

以下のようにkvtlctlを使うことでgRPCでアクセスすることができる。

./kvtctl.sh help

vttablesをインストール

Vitess tabletがスケールアウトを実現する上で必要である。以下のようにデプロイをします。

./vttablet-up.sh

ここでリソースが足りなかったのでスケールアウトさせました。

gcloud container clusters resize vitess-cluster --size=5

これでも足りなかったです。というよりCPUが足りないのでスケールアウトというよりはスケールアップをしないといけないのです。

以下のコマンドで確認できます。

./kvtctl.sh ListAllTablets test

MySQLの初期化

./kvtctl.sh InitShardMaster -force test_keyspace/0 vttablet-100

再度確認すると以下のようになっている。

./kvtctl.sh ListAllTablets test

test-100 test_keyspace 0 master 10.64.1.6:15002 10.64.1.6:3306 []
test-101 test_keyspace 0 replica 10.64.2.5:15002 10.64.2.5:3306 []
test-102 test_keyspace 0 replica 10.64.0.7:15002 10.64.0.7:3306 []
test-103 test_keyspace 0 rdonly 10.64.1.7:15002 10.64.1.7:3306 []
test-104 test_keyspace 0 rdonly 10.64.2.6:15002 10.64.2.6:3306 []

MySQLのスキーマを書く

./kvtctl.sh ApplySchema -sql "$(cat create_test_table.sql)" test_keyspace

これは以下のようになっています。

CREATE TABLE messages (
  page BIGINT(20) UNSIGNED,
  time_created_ns BIGINT(20) UNSIGNED,
  message VARCHAR(10000),
  PRIMARY KEY (page, time_created_ns)
) ENGINE=InnoDB

Backupをとる

以下のようにしてバックアップを取ってみます。

./kvtctl.sh Backup test-104

vgateをデプロイ

このままではルーティングをしてくれるvgateがないためアクセスできません。

./vtgate-up.sh

のようにして立ち上げます。

アプリケーション側のコードを書いてデプロイ

これをvgateあてに接続すれば大丈夫です。

今回はコードは省略します。

クリーンアップ

以下のようにしてクリーンアップします。

./vtgate-down.sh
./vttablet-down.sh
./vtctld-down.sh
./etcd-down.sh

Vitess Client Library

Goのライブラリは以下の通りです。

github.com

このvt以下にVitess用のライブラリが入っています。

api一つにつき、Protocol BufferのServiceが一つ定義されているのでimportして使うとAPIを使うことができる。

まとめ

  • Vitess ClusterはKubernetes Cluster内で構築されたクラスタであり、決してKubernetesクラスタが二つあるわけではない
  • etcd Clusterも構築しないといけないので面倒
  • アプリケーション側は特に意識する必要があるものはない

参考文献