Vitess(ヴィテス)をさわってみよう!(Part 1)
Vitess(ヴィテス)とは
MySQLインスタンスの大規模クラスタをデプロイ、拡張、管理するためのデータベースソリューションです。
本ソリューションはもともとYouTubeのバックエンドであるMySQLクラスタで利用されていましたが、GoogleがOSSとして公開し誰でも利用可能となりました。
2018年のMySQL Awardで表彰されたり、Cloud Native Computing Foundation (CNCF)のインキュベーションプロジェクトとなったりと 今後が非常に注目されるソリューションです。
Vitessの主な機能は以下のとおりです。
- コネクションプール
- ACL
- パフォーマンス監視
- MySQLトポロジ管理インタフェースの提供
- 水平分割/垂直分割
今回は、チュートリアルをもとに可能な限りVitessを解明していきたいと思います。
ドキュメント
はじめに
Vitessのアーキテクチャは上記のようになっています。
vtgateやvttablet等多くのソフトウェアが連携して機能を実現していることが確認できます。
これらは検証目的として一般的なOS上でも起動する手順も提供されていますがプロダクション環境ではコンテナとオーケストレーションツール下での可動が推奨されています。
代表的なものとしてDockerとKubernatesが挙げられます。
各機能の詳細は本資料のtopologyをご確認ください。
検証環境
今回は、CentOS 7.5上のminikubeで検証を行いました。
お試し頂く際にはminikubeをご準備ください。
インストール
Tutorialsに従ってインストールを行います。
まずはVitessをDownloadします。
1 |
$ git clone https://github.com/vitessio/vitess.git |
VitessはKubernates(minikube)上で利用する場合にはメタデータリポジトリとしてetcdを使用します。
そのため、先にetcdのPodを起動しておく必要があります。
公式の手順に従いetcdをインストールしましょう。
1 2 3 |
$ git clone https://github.com/coreos/etcd-operator.git $ cd etcd-operator $ example/rbac/create_role.sh |
次にHelmをインストールする必要があります。
HelmはGolangのソフトウェアですので、単一のバイナリで動作します。
以下のページからHelmを入手し、PATHの通った場所に配置ください。
https://github.com/helm/helm/releases
次にhelm initでHelmの利用準備を行います
1 |
$ helm init |
これでminikube側の準備は完了です。
VitessにアクセスするためのClientツールをインストールします。
まずはGolang 1.11以上がインストールされている事をご確認ください。
1 2 |
$ go version go version go1.11.5 linux/amd64 |
次にvtctlclientをインストールします。vtctlclientはVitessの管理用コマンドラインツールです。
1 |
$ go get vtctlclient |
最後にMySQL Clientをインストールします。
1 |
$ yum install mysql |
以上で前準備は完了です。
Helm Chartのインストール(Vitessの構築)
クローンしたVitessのディレクトリにはチュートリアルのためのexamplesディレクトリが含まれており、この配下のyamlをapplyしていくことで、各操作を行います。
また、 [clone dir]/helmにHelm Chartが含まれています。
HelmはKubernatesにおけるパッケージマネージャに位置づけられており、Helm Chartは各ソフトウェアを構築するための一連のyamlファイル等の集合です。
早速Helm Chartを使い、Vitessをデプロイします。
1 2 |
$ cd examples/helm $ helm install ../../helm/vitess -f 101_initial_cluster.yaml |
kubectlで作成されたpodとjobを確認すると、以下の通り作成されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ kubectl get pods,jobs NAME READY STATUS RESTARTS AGE pod/commerce-apply-schema-initial-9p5kb 0/1 Completed 0 14m pod/commerce-apply-vschema-initial-6stgx 0/1 Completed 0 14m pod/etcd-global-pt92xbswk5 1/1 Running 0 14m pod/etcd-operator-84db9bc774-cm77h 1/1 Running 0 15m pod/etcd-zone1-9tps7f6rg8 1/1 Running 0 14m pod/vtctld-9b7d47bbc-ttwb8 1/1 Running 2 14m pod/vtgate-zone1-67ddd6c959-zn9hs 1/1 Running 3 14m pod/zone1-commerce-0-init-shard-master-w7rfj 0/1 Completed 0 14m pod/zone1-commerce-0-rdonly-0 6/6 Running 0 14m pod/zone1-commerce-0-replica-0 6/6 Running 0 14m pod/zone1-commerce-0-replica-1 6/6 Running 0 14m NAME COMPLETIONS DURATION AGE job.batch/commerce-apply-schema-initial 1/1 116s 14m job.batch/commerce-apply-vschema-initial 1/1 108s 14m job.batch/zone1-commerce-0-init-shard-master 1/1 114s 14m |
101_initial_cluster.yamlの各設定値は
[clone dir]/helm/vitess/values.yamlに定義されています。
内容にはetcd, backup, vtgateなどのパラメータ定義があり、vttabletのセクションには様々な定義があります。
例えばvttabletのDatabaseに使用するImageを定義したり
1 2 3 4 5 6 7 |
# Default values for vttablet resources defined in 'topology' vttablet: vitessTag: helm-1.0.6 : mysqlImage: percona:5.7.23 # mysqlImage: mysql:5.7.24 # mysqlImage: mariadb:10.3.11 |
データボリュームのサイズを決定したり
1 2 3 4 5 6 7 8 9 10 11 12 |
# PVC for mysql dataVolumeClaimAnnotations: dataVolumeClaimSpec: # pd-ssd (Google Cloud) # managed-premium (Azure) # standard (AWS) - not sure what the default class is for ssd # Note: Leave storageClassName unset to use cluster-specific default class. #storageClassName: pd-ssd accessModes: ["ReadWriteOnce"] resources: requests: storage: 10Gi |
Percona Monitoring and Managementや、Orchestratorを同時に起動するためのセクションがあったりします。
1 2 3 4 5 6 7 |
# Default values for pmm pmm: enabled: false : orchestrator: enabled: false image: vitess/orchestrator:3.0.14 |
今回は有効化しませんでしたが、ご興味があればお試しください。
接続
examplesディレクトリ配下の
kmysql.shを使用して接続ができます。
実際の接続はvtgateに対して行われ、いずれかのvttabletにルーティングされます。
kmysql.shの内容を見てみましょう。
1 2 3 4 |
host=$(minikube service vtgate-zone1 --format "{{.IP}}" | tail -n 1) port=$(minikube service vtgate-zone1 --format "{{.Port}}" | tail -n 1) : mysql -h "$host" -P "$port" $* |
minikubeを使い、vtgate-zone1のIPとPortを取得、あとは通常通りmysqlに接続しています。
コマンドの結果は以下となりました。
1 2 3 4 |
$ minikube service vtgate-zone1 --format "{{.IP}}" | tail -n 1 172.26.10.75 $ minikube service vtgate-zone1 --format "{{.Port}}" | tail -n 1 32077 |
172.26.10.75はminikubeホストのインターナルIPです。
特に問題なく接続ができました。
1 2 |
$ mysql -h 172.26.10.75 -P 32077 MySQL [(none)]> |
なお、32077はkube-proxyによって外部に公開されています。
1 2 |
$ ss -nltp | grep 32077 LISTEN 0 128 :::32077 :::* users:(("kube-proxy",pid=14636,fd=13)) |
外部のデスクトップからも接続することができました。
1 2 |
$ mysql -h <hostserverip> -P 32077 mysql> |
vtgate-zone1のPodの情報を見てみると以下のようになっています。
1 2 |
$ kubectl get svc | grep vtgate-zone1 vtgate-zone1 NodePort 10.105.88.160 <none> 15001:30563/TCP,15991:30502/TCP,3306:32077/TCP 56m |
minikubeの内部ネットワークで割り当てられたIPは10.105.88.160です。
zone1とはなんでしょうか。
zone1は <clone dir>/helm/vitess/values.yaml のtopologyのセクションで定義されているCellの1つです。
TopologyはVitessのメタデータの定義です。
CellはVitessを構成する一連のPodをまとめる論理的な単位であり、個々のデータセンターを表現できます。
チュートリアルの設定ではtopology内のセルははzone1しかありませんでしたので、1つのみです。
vtgatewayへのトラフィックは、適切なvttablet(つまりその裏のMySQL)へルーティングされます。
本当にルーティングがされるのか確認するために、チュートリアルを先に進めましょう。
スキーマの確認/vttabletの追加/垂直分割
接続が行えましたので、初期ロードされているデータを見てみます。
VitessではMySQLでいうdatabaseをkeyspaceと言い、水平分割・垂直分割はこのkeyspaceの単位で行われます。
keyspaceはshow databasesで確認できます
1 2 3 4 5 6 |
MySQL [(none)]> show databases; +-----------+ | Databases | +-----------+ | commerce | +-----------+ |
テーブルを確認するコマンドもMySQLと同じです
1 2 3 4 5 6 7 8 |
MySQL [commerce]> show tables from commerce; +--------------------+ | Tables_in_commerce | +--------------------+ | corder | | customer | | product | +--------------------+ |
corderテーブルを確認しても、普遍的なInnoDBのテーブルに見えます。
1 2 3 4 5 6 7 8 9 10 |
MySQL [commerce]> show create table corder\G *************************** 1. row *************************** Table: corder Create Table: CREATE TABLE `corder` ( `order_id` bigint(20) NOT NULL AUTO_INCREMENT, `customer_id` bigint(20) DEFAULT NULL, `sku` varbinary(128) DEFAULT NULL, `price` bigint(20) DEFAULT NULL, PRIMARY KEY (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
MySQL(Percona Server)のImageを使用しているので当然でしょう。
MySQL自体は特にカスタマイズされたものではなく、シャーディングやルーティングはvtgatewayやvttabletの役目です。
用意されているテストデータの挿入し、データを確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
$ ./kmysql.sh < ../common/insert_commerce_data.sql $ ./kmysql.sh --table < ../common/select_commerce_data.sql Using commerce/0 Customer +-------------+--------------------+ | customer_id | email | +-------------+--------------------+ | 1 | alice@domain.com | | 2 | bob@domain.com | | 3 | charlie@domain.com | | 4 | dan@domain.com | | 5 | eve@domain.com | +-------------+--------------------+ Product +----------+-------------+-------+ | sku | description | price | +----------+-------------+-------+ | SKU-1001 | Monitor | 100 | | SKU-1002 | Keyboard | 30 | +----------+-------------+-------+ COrder +----------+-------------+----------+-------+ | order_id | customer_id | sku | price | +----------+-------------+----------+-------+ | 1 | 1 | SKU-1001 | 100 | | 2 | 2 | SKU-1002 | 30 | | 3 | 3 | SKU-1002 | 30 | | 4 | 4 | SKU-1002 | 30 | | 5 | 5 | SKU-1002 | 30 | +----------+-------------+----------+-------+ |
結果に
Using commerce/0 という文字列が確認できます。
select_commerce_data.sqlでは、
use commerce/0 というコマンドでkeyspaceをuseしています。
0はkeyspace idと呼ばれるデータの分割キーです。
keyspaceは分散される事を前提とした仕組みなので、どのシャードをuseするかという指定を行っています。
このようにkeyspace idを選択してデータを確認することは可能ですが、テーブルの各行にkeyspace idは紐付けられているため、アプリケーションはそれを意識しなくても問題ありません。
どのようにテーブルやデータを分散させるかというKeyspace等の定義をVSchemaといい、ユーザがこれを定義・適用する必要があります。
それではVSchemaを更新していきましょう。
ここでは、どのような更新が行われるかは概要の説明にとどまりますが、詳細はTutorialsをご確認ください。
1 2 3 4 5 |
$ export release=$(helm ls -q|tail -1) $ helm upgrade $release ../../helm/vitess/ -f 201_customer_keyspace.yaml <-- customerというkeyspaceを作成 $ helm upgrade $release ../../helm/vitess/ -f 202_customer_tablets.yaml <-- customer keyspaceを分散させるためのvttabletを作成し、commerce.corder, commerce.customerの定義をcustomer keyspaceにコピー $ helm upgrade $release ../../helm/vitess/ -f 203_vertical_split.yaml <-- commerce.corder, commerce.customerのデータをcustomerの同テーブルにコピー(垂直分割) $ helm upgrade $release ../../helm/vitess/ -f 206_clean_commerce.yaml <-- コピー完了後はトラフィックが切り替えられるので、コピー元テーブルのDROP |
これでcommerce.productとcustomer.corder, customer.customerのようにテーブルが分散されました。
分割後の確認
いくつかの状態を確認していきます。
まず、新しいvttablet が作成されていることが確認できます。
1 2 3 4 5 6 7 |
$ kubectl get po | grep -i customer customer-apply-vschema-vsplit-jjxbc 0/1 Completed 0 6m17s customer-copy-schema-0-v5lzz 0/1 Completed 0 6m17s zone1-customer-0-init-shard-master-t8nk7 0/1 Completed 0 6m17s zone1-customer-0-rdonly-0 6/6 Running 0 6m17s zone1-customer-0-replica-0 6/6 Running 0 6m17s zone1-customer-0-replica-1 6/6 Running 0 6m17s |
チュートリアルの構成では、replica-0, 1とrdonly(readonly)のMySQLが存在します。
replicaはいずれかがマスタになります。
commerce keyspaceからcorder, customerテーブルは削除されました。
1 2 3 4 |
$ mysql -h10.105.88.160 -t -e "select @@hostname from commerce.customer limit 1" ERROR 1105 (HY000) at line 1: vtgate: http://vtgate-zone1-67ddd6c959-zn9hs:15001/: target: commerce.0.master, used tablet: zone1-1564760600 (zone1-commerce-0-replica-0.vttablet), vttablet: rpc error: code = InvalidArgument desc = table customer not found in schema (CallerID: userData1) $ mysql -h10.105.88.160 -t -e "select @@hostname from commerce.corder limit 1" ERROR 1105 (HY000) at line 1: vtgate: http://vtgate-zone1-67ddd6c959-zn9hs:15001/: target: commerce.0.master, used tablet: zone1-1564760600 (zone1-commerce-0-replica-0.vttablet), vttablet: rpc error: code = InvalidArgument desc = table corder not found in schema (CallerID: userData1) |
それではやっとルーティングを確認してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$ mysql -h10.105.88.160 -t -e "select @@hostname from commerce.product limit 1" +----------------------------+ | @@hostname | +----------------------------+ | zone1-commerce-0-replica-0 | +----------------------------+ $ mysql -h10.105.88.160 -t -e "select @@hostname from customer.corder limit 1" +----------------------------+ | @@hostname | +----------------------------+ | zone1-customer-0-replica-0 | +----------------------------+ $ mysql -h10.105.88.160 -t -e "select @@hostname from customer.customer limit 1" +----------------------------+ | @@hostname | +----------------------------+ | zone1-customer-0-replica-0 | +----------------------------+ |
透過的に適切なkeyspaceにルーティングされている様子が確認できました。
素晴らしい動作です。
まとめ
今回の検証では、Vitessのインストールと接続、垂直分割にルーティング確認まで行うことができました。
しかしながら、Vitessはまだまだ以下のような機能があり、中でも水平分割はVitessを使う動機になり得る機能でしょう。
- 水平分割
- コネクションプール
- ACL
- レプリケーションにおける自動フェイルオーバ(Orchestrator)
- 管理用WEB UI(Percona Monitoring and Management/vtctld)
- and more..
今回は初回のインストール編ということでした。
ぜひこの先進的なソリューションを実際にお試しください。
Let’s Enjoy Vitess!