メインコンテンツへスキップ
  1. Blogs/

MySQL InnoDB Cluster2 -MySQL Router-

·3143 文字·
Blog Kubernetes Mysql
hiroki
著者
hiroki
A little bit about you
目次
mysql-innodb-cluster - 関連記事
2: << この記事 >>

はじめに
#

第1回では、MySQL InnoDB Clusterのdeploy方法について紹介しましたが、今回はInnoDBのコンポーネントの1つであるMySQL-Routerについて紹介します。

1. MySQL-Routerとは
#

k8sでpodにアクセスするには通常Serviceが利用されますが、ServiceによるpodへのルーティングはラウンドロビンのためPrimary/Secondaryを区別する必要があるmysqlには不適切です。

# SecondaryにルーティングされるとReadOnlyになるのでk8s任せはNG
            mysql-1(Primary, RW)
Service ->  mysql-2(Secondary, RO)
            mysql-3(Secondary, RO)

そこでMySQL InnoDB ClusterではMySQL-Routerが自動でdeployされます。このMySQL-Routerは優れもので以下の機能を備えています。 公式docs

  • Primary/Secondaryを自動で判別して適切なルーティングの実施
  • FailoverにてPrimaryが変更された場合でも自動で追従
  • ReadはSecondary、WriteはPrimaryに分散させることでパフォーマンスの向上(R/W Split)
    img001
    Figure by MySQL

従ってMySQL-Routerを使った場合の通信は、k8sのServiceがMySQL-Routerのpodに通信を渡すことになります。

# Writeの場合(Primaryに必ずルーティング)
            mysql-router
Service ->  mysql-router -> mysql-1(primary, RW)
            mysql-router

# Readの場合(Secondaryにルーティング)
            mysql-router   
Service ->  mysql-router ->  mysql-2(secondary, RO)
            mysql-router     mysql-3(secondary, RO)

本来MySQL-Routerのdeployには、mysqlrouter.cnfを作成して、接続するDB等の情報を記載する必要や、MySQL-Router自体を複数用意して分散させる必要があります。 参考(公式HP)

しかしmysql-operatorやk8sのReplica数の設定によってこれらの手順を自動で実施してくれます。

2. Portによる挙動の違い
#

MySQL-Routerには大きく分けて以下の3つのモードがありアクセスするportによって動作を制御できます。

port 役割
6446 Primaryへアクセス[RW]
6447 Secondaryのいずれかにアクセス[RO]
6450 WriteはPrimary、ReadはSecondaryに自動で判別[RW Split]

RW SplitはMySQL8.2からの新機能です。 参考(The Oracle MySQL Japan Blog)

また今回は紹介しませんがmysqlx用のportも存在します。 公式HP

k8sで展開したMySQL RouterではServiceを見てみると、defaultの:3306TargetPort: 6446/TCPにルーティングされているので、常にPrimaryにアクセスする形になります。適宜変更するか第3回で紹介するhelmのカスタマイズによってdefaultの挙動を変更しましょう。

$ kubectl describe service mysql-cluster


IP:                       10.96.237.122
IPs:                      10.96.237.122

Port:                     mysql  3306/TCP
TargetPort:               6446/TCP
NodePort:                 mysql  31117/TCP
Endpoints:                192.168.2.52:6446

Port:                     mysqlx  33060/TCP
TargetPort:               6448/TCP
NodePort:                 mysqlx  31811/TCP
Endpoints:                192.168.2.52:6448

Port:                     mysql-alternate  6446/TCP
TargetPort:               6446/TCP
NodePort:                 mysql-alternate  32475/TCP
Endpoints:                192.168.2.52:6446

Port:                     mysqlx-alternate  6448/TCP
TargetPort:               6448/TCP
NodePort:                 mysqlx-alternate  30889/TCP
Endpoints:                192.168.2.52:6448

Port:                     mysql-ro  6447/TCP
TargetPort:               6447/TCP
NodePort:                 mysql-ro  32048/TCP
Endpoints:                192.168.2.52:6447

Port:                     mysqlx-ro  6449/TCP
TargetPort:               6449/TCP
NodePort:                 mysqlx-ro  32510/TCP
Endpoints:                192.168.2.52:6449

Port:                     mysql-rw-split  6450/TCP
TargetPort:               6450/TCP
NodePort:                 mysql-rw-split  30946/TCP
Endpoints:                192.168.2.52:6450

Port:                     router-rest  8443/TCP
TargetPort:               8443/TCP
NodePort:                 router-rest  30997/TCP
Endpoints:                192.168.2.52:8443

3. RW Splitの挙動
#

MySQL-Routerの挙動がわかったので、実際にRW Splitが実現しているか確認します。

deployされているInnoDB Clusterは以下の通りで、mysql-cluster-0がPrimaryです。

$ kubectl get pods -n dev
NAME                                    READY   STATUS    RESTARTS   AGE
mysql-cluster-0                         2/2     Running   0          3h6m
mysql-cluster-1                         2/2     Running   0          3h6m
mysql-cluster-2                         2/2     Running   0          3h6m
mysql-cluster-router-57c657f6cf-xtwwm   1/1     Running   0          3h5m

$ kubectl logs mysql-cluster-router-57c657f6cf-xtwwm -n dev
Metadata for cluster 'mysql_cluster' has 3 member(s), single-primary: 
     mysql-cluster-0.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RW
     mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
     mysql-cluster-1.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO

この状態でMySQLの:6450(RW Split)にアクセスします。

$ mysql -h 192.168.1.220 -P 6450 -p
Enter password: 
mysql> 

書き込みモードをcheckすると、mysql-cluster-0とPrimaryにアクセスし、read_onlyもfalseであることがわかります。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@hostname,@@port,@@read_only;
+-----------------+--------+-------------+
| @@hostname      | @@port | @@read_only |
+-----------------+--------+-------------+
| mysql-cluster-0 |   3306 |           0 |
+-----------------+--------+-------------+
1 row in set (0.01 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

次に読み込みモードをcheckすると、mysql-cluster-1とSecondaryにアクセスし、read_onlyもtrueになっています。

mysql> START TRANSACTION READ ONLY;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @@hostname,@@port,@@read_only;
+-----------------+--------+-------------+
| @@hostname      | @@port | @@read_only |
+-----------------+--------+-------------+
| mysql-cluster-2 |   3306 |           1 |
+-----------------+--------+-------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

これでRW Splitによって同一SessionであってもWriteはPrimaryにReadはSecondaryに自動で振り分けてくれることが確認できました。

session毎に1つのPrimaryと1つのSecondaryが選ばれるので、同一Sessionでは常に同じSecondarymysql-cluster-2が選ばれます。 参考(公式doc)

違うSecondaryも使用したい場合はsessionを変える必要があるので注意しましょう。

$ mysql -h 192.168.1.220 -P 6450 -p
Enter password: 

mysql> START TRANSACTION READ ONLY;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@hostname,@@port,@@read_only;
+-----------------+--------+-------------+
| @@hostname      | @@port | @@read_only |
+-----------------+--------+-------------+
| mysql-cluster-1 |   3306 |           1 |
+-----------------+--------+-------------+
1 row in set (0.00 sec)

4. DB障害の挙動
#

PrimaryのNodeが故障した場合にRW Splitの挙動はどうなるでしょうか? 故障を模擬するためPrimaryのpodを削除してみます

$ kubectl delete pod mysql-cluster-0 -n dev
pod "mysql-cluster-0" deleted

すると、同一session中であればReconnectが発生し、Failover後のmysql-cluster-2繋がるようになりました。

mysql> START TRANSACTION;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id:    0
Current database: *** NONE ***

Query OK, 0 rows affected (0.03 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@hostname,@@port,@@read_only;
+-----------------+--------+-------------+
| @@hostname      | @@port | @@read_only |
+-----------------+--------+-------------+
| mysql-cluster-2 |   3306 |           0 |
+-----------------+--------+-------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

Routerのlogにはmysql-cluster-0が止まってから、mysql-cluster-2が新たなPrimaryとして選出される様子を見ることができます。(今回はnode故障ではなくpod単体削除のため、mysql-cluster-0はk8sによって自動で復旧しSecondaryとして再登録されています。)

$ kubectl logs mysql-cluster-router-57c657f6cf-xtwwm -n dev
2024-06-09 11:15:34 metadata_cache WARNING [7f8508763700] Failed fetching metadata from metadata server on mysql-cluster-0.mysql-cluster-instances.dev.svc.cluster.local:3306 - No result returned for v2_this_instance metadata query
2024-06-09 11:15:34 metadata_cache INFO [7f8508763700] Connected with metadata server running on mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306
2024-06-09 11:15:34 metadata_cache WARNING [7f8508763700] GR member mysql-cluster-0.mysql-cluster-instances.dev.svc.cluster.local:3306 (51aeada7-2630-11ef-8617-56a8e7260f34), state: 'Online' missing in the metadata, ignoring
2024-06-09 11:15:34 metadata_cache INFO [7f8508763700] Potential changes detected in cluster after metadata refresh (view_id=0)
2024-06-09 11:15:34 metadata_cache INFO [7f8508763700] Metadata for cluster 'mysql_cluster' has 2 member(s), single-primary: 
2024-06-09 11:15:34 metadata_cache INFO [7f8508763700]     mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
2024-06-09 11:15:34 metadata_cache INFO [7f8508763700]     mysql-cluster-1.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
2024-06-09 11:15:34 routing INFO [7f8508763700] Stop accepting connections for routing routing:bootstrap_x_rw listening on 0.0.0.0:6448
2024-06-09 11:15:34 routing INFO [7f8508763700] Disconnecting client 192.168.1.217:16997 from server 
2024-06-09 11:15:34 routing INFO [7f8508763700] Routing routing:bootstrap_rw_split listening on '0.0.0.0:6450' got request to disconnect 1 invalid connections: metadata change
2024-06-09 11:15:34 routing INFO [7f8508763700] Stop accepting connections for routing routing:bootstrap_rw listening on 0.0.0.0:6446
2024-06-09 11:15:35 metadata_cache INFO [7f8508763700] Potential changes detected in cluster after metadata refresh (view_id=0)
2024-06-09 11:15:35 metadata_cache INFO [7f8508763700] Metadata for cluster 'mysql_cluster' has 2 member(s), single-primary: 
2024-06-09 11:15:35 metadata_cache INFO [7f8508763700]     mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RW
2024-06-09 11:15:35 metadata_cache INFO [7f8508763700]     mysql-cluster-1.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
2024-06-09 11:15:35 routing INFO [7f8508763700] Start accepting connections for routing routing:bootstrap_x_rw listening on '0.0.0.0:6448'
2024-06-09 11:15:35 routing INFO [7f8508763700] Start accepting connections for routing routing:bootstrap_rw listening on '0.0.0.0:6446'
2024-06-09 11:17:13 metadata_cache INFO [7f8508763700] Potential changes detected in cluster after metadata refresh (view_id=0)
2024-06-09 11:17:13 metadata_cache INFO [7f8508763700] Metadata for cluster 'mysql_cluster' has 2 member(s), single-primary: 
2024-06-09 11:17:13 metadata_cache INFO [7f8508763700]     mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RW
2024-06-09 11:17:13 metadata_cache INFO [7f8508763700]     mysql-cluster-1.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
2024-06-09 11:17:14 metadata_cache INFO [7f8508763700] Potential changes detected in cluster after metadata refresh (view_id=0)
2024-06-09 11:17:14 metadata_cache INFO [7f8508763700] Metadata for cluster 'mysql_cluster' has 3 member(s), single-primary: 
2024-06-09 11:17:14 metadata_cache INFO [7f8508763700]     mysql-cluster-2.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RW
2024-06-09 11:17:14 metadata_cache INFO [7f8508763700]     mysql-cluster-1.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO
2024-06-09 11:17:14 metadata_cache INFO [7f8508763700]     mysql-cluster-0.mysql-cluster-instances.dev.svc.cluster.local:3306 / 33060 - mode=RO

5. Router障害時の挙動
#

今度はRouterを2台deployし、片方のRouterをdelete + 直後にmysqladmin pingを実施します。

削除した直後のmysqld is aliveとなっているので生きている方のRouterを使って継続してDBにアクセスできていることがわかります。 またdeleteした直後に新しいRouterがContainerCreatingで作成されるので、直ぐに冗長構成へ復帰することもできています。

$ date &&\
  kubectl delete pod mysql-cluster-router-6cfb6c567b-n4jkt -n prd &&\
  kubectl get pods -n prd | grep router &&\
  mysqladmin -h 192.168.1.220 -p${MYSQL_PASSWORD} ping &&\
  sleep 5 &&\
  mysqladmin -h 192.168.1.220 -p${MYSQL_PASSWORD} ping &&\
  date
Sun Jun  9 11:54:20 AM UTC 2024
pod "mysql-cluster-router-6cfb6c567b-n4jkt" deleted
mysql-cluster-router-6cfb6c567b-gqgds   1/1     Running             0          98s
mysql-cluster-router-6cfb6c567b-pvp69   0/1     ContainerCreating   0          1s
mysqld is alive
mysqld is alive
Sun Jun  9 11:54:26 AM UTC 2024

おわりに
#

これでMySQL InnoDB Clusterのメインの機能については紹介できました。k8sとHelmさえ使えれば、非常に手軽に耐障害性 + RW Splitによるパフォーマンス向上のDBを作成することができます。(構成としては複雑なので運用時のトラブルが怖いですが)

次回はHelm chartを変更してカスタマイズする方法について紹介します。

mysql-innodb-cluster - 関連記事
2: << この記事 >>

Related

MySQL InnoDB Cluster1 -k8sにdeploy-
·3727 文字
Blog Kubernetes Mysql
pyvmomiで自動化7 -HoLを使った検証環境の用意-
·1189 文字
Blog VMware VSphere Pyvmomi Python
iphoneのオートメーションで特定APPのみVPNを有効化
·684 文字
Blog IPhone Homelab