ProxySQLでInnoDB Clusterもどきを作成する
これはなに?
InnoDB Clusterは、MySQL Router + MySQL Shell + GroupReplication の3つで構成される高可用性ソリューションだが、MySQL RouterとMySQL Shellを使わなくてもInnoDB Clusterと同様のこと (アプリケーション側とMySQL側のフェイルオーバー) を実現することは可能。
今回は、ProxySQL + GroupReplication を使用して、アプリケーション側のフェイルオーバーを行う方法について書こうと思う。
構成
Hyper-V上のUbuntu 18.04にLXCコンテナ (全てUbuntu 18.04) を立てて試してみた。
InnoDB Clusterの場合は、MySQL Routerが mysql_innodb_cluster_metadata
スキーマを参照するためMySQL Shellが必須だが、今回の場合は別に必要はない。(ただ、MySQL Shell経由でGroupReplicationを組んだほうが簡単ではある。)
今回は一応、手動でGroupReplicationを組んでみることにする。
ノード | IPアドレス | ホスト名 |
---|---|---|
GroupReplication Primary | 10.0.3.11 | gr_primary |
GroupReplication Secondary1 | 10.0.3.12 | gr_secondary1 |
GroupReplication Secondary2 | 10.0.3.13 | gr_secondary2 |
ProxySQL | 10.0.3.21 | proxysql |
準備
GroupReplicationの構築
Primaryノードの設定ファイルは以下のようにした。Secondaryノードに関しては、server_id
とreport_host
, loose-group_replicaton_local_address
以外は同じため省略する。
[mysqld] server_id=11 # 各ノードで一意な値を設定 gtid_mode=ON enforce_gtid_consistency=ON binlog_checksum=NONE report_host="10.0.3.11" # 自身のIPアドレスを指定する default_authentication_plugin=mysql_native_password plugin_load=group_replication.so loose-group_replication_group_name="b73bffe9-5eff-4e32-8bed-fddb45b1999b" loose-group_replication_start_on_boot=off loose-group_replication_local_address="10.0.3.11:33061" # 自身のIPアドレス loose-group_replication_group_seeds="10.0.3.11:33061,10.0.3.12:33061,10.0.3.13:33061" loose-group_replication_bootstrap_group=off
また、ProxySQLは caching_sha2_password
認証に対応していない ため、default_authentication_plugin
の値は mysql_native_password
とする必要がある。
ProxySQL doesn't accept connections (frontend connections and connections to Admin) if the client tries to use
caching_sha2_password
authentication plugin. If clients are using libmysqlclient from MySQL 8.0 (that defaults tocaching_sha2_password
), they must explicitly usemysql_native_password
.
GroupReplicationを構成する各ノードのmysqlに接続して、レプリケーション用のユーザを作成する。
mysql> create user repl@'%' identified by 'password'; mysql> grant replication slave on *.* to repl@'%'; mysql> change master to master_user='repl', master_password='password' for channel 'group_replication_recovery'; mysql> reset master;
次にPrimaryノードとなる最初の一台でのみ以下の作業を行う。Primaryノード以外でも group_replication_bootstrap_group
をONにした場合、同じ名前のグループが複数起動されてしまうので注意。
Primary> set global group_replication_bootstrap_group=ON; Primary> start group_replication; Primary> set global group_replication_bootstrap_group=OFF;
続いて、SecondaryノードでもGroupReplicatonを開始する。
Secondary> start group_replication;
これで、GroupReplicationの構築が完成。
mysql> select member_host,member_state,member_role from performance_schema.replication_group_members; +-------------+--------------+-------------+ | member_host | member_state | member_role | +-------------+--------------+-------------+ | 10.0.3.11 | ONLINE | PRIMARY | | 10.0.3.12 | ONLINE | SECONDARY | | 10.0.3.13 | ONLINE | SECONDARY | +-------------+--------------+-------------+
ProxySQLのインストール
次に、ProxySQLをインストールしていく。ProxySQLには1.4系と2.0系が存在するが、今回は1.4系を使用した。2.0系では色々な機能が追加されているとか (未確認)。
$ wget https://repo.percona.com/apt/percona-release_0.1-10.bionic_all.deb $ sudo dpkg -i percona-release_0.1-10.bionic_all.deb $ sudo apt update $ sudo apt install proxysql $ proxysql --version ProxySQL version 1.4.16-percona-1.1, codename Truls
ProxySQLには管理インターフェイスから設定を変更する方法と、設定ファイル (/etc/proxysql.cnf
) から設定を変更する方法の2通りが可能だが、今回は管理インターフェイスで設定を行う。両者の違いは、パラメータを動的に変更可能かどうかで、管理インターフェイスから設定する場合は多くのパラメータを動的に変更できる。
sysスキーマに監視用ビューを作成する
lefredさんのgistに公開されてる additional_to_sys_GR.sql を使用してGroupReplicationの状態を監視するビューを作成する。 Primaryノードで以下のコードを実行する。
$ mysql -uroot -p < addition_to_sys_GR.sql
すると、以下のようなビューが作成される。 transactions_behind
と transactions_to_cert
の値はそれぞれ applier queue と certifier queue にキューイングされるトランザクション数に相当する (ただし、ProxySQLはtransactions_to_cert
の値を多分参照してなさそう)。詳しくは公式の Flow Control を参照。
mysql> select * from sys.gr_member_routing_candidate_status; +------------------+-----------+---------------------+----------------------+ | viable_candidate | read_only | transactions_behind | transactions_to_cert | +------------------+-----------+---------------------+----------------------+ | YES | NO | 0 | 0 | +------------------+-----------+---------------------+----------------------+
また、ProxySQLがこのビューを参照できるように、監視用ユーザーを作成しておく。
mysql> create user 'monitor'@'%' identified by 'monitor'; mysql> grant select on sys.* to 'monitor'@'%';
ProxySQLに接続先サーバー情報を追加する
mysqlクライアントを使ってProxySQLの管理インターフェイスに接続し、GroupReplicationに接続するために必要な設定を行う。
# 管理インターフェイスのポートは6032 $ mysql -uadmin -padmin -h127.0.0.1 -P6032 --prompt='Admin> ' # 書き込みグループを1, 読み込みグループは2とする Admin> INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup) VALUES (1, 2); Admin> INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (1, '10.0.3.11',3306), (1, '10.0.3.12',3306), (1, '10.0.3.13',3306); Admin> INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (2, '10.0.3.11',3306), (2, '10.0.3.12',3306), (2, '10.0.3.13',3306); Admin> select hostgroup_id, hostname, status from mysql_servers; +--------------+-----------+--------+ | hostgroup_id | hostname | status | +--------------+-----------+--------+ | 1 | 10.0.3.11 | ONLINE | | 1 | 10.0.3.12 | ONLINE | | 1 | 10.0.3.13 | ONLINE | | 2 | 10.0.3.11 | ONLINE | | 2 | 10.0.3.12 | ONLINE | | 2 | 10.0.3.13 | ONLINE | +--------------+-----------+--------+ # 変更をRUNTIMEに反映させ、DISKに保存する Admin> LOAD MYSQL SERVERS TO RUNTIME; Admin> SAVE MYSQL SERVERS TO DISK;
GroupReplicatonの監視設定を行う
ProxySQL1.4から mysql_group_replication_hostgroups
というテーブルが追加され、自作スクリプトを用意しなくてもGroupReplicationの状態を監視できるようになった。
Admin> INSERT INTO mysql_group_replication_hostgroups (writer_hostgroup,backup_writer_hostgroup,reader_hostgroup, offline_hostgroup,active,max_writers,writer_is_also_reader,max_transactions_behind) VALUES (1,3,2,4,1,1,0,100); Admin> LOAD MYSQL SERVERS TO RUNTIME; Admin> SAVE MYSQL SERVERS TO DISK;
R/W, R/O分割を行う
ProxySQLでは、Read-Write (RW) と Read-Only (RO) の振り分け方として、主に以下の3つの方法が可能。それぞれの方法について説明を行う。
- 接続ポートを分離する
- 接続ユーザーを分離する
- クエリの種類によって分離する
1. 接続ポートを分離する場合
接続ポートを分離することによってR/W, R/O分割を行う。R/W用ポートは6401, R/O用ポートは6402を使用した。以下の内容はProxySQL Wiki) を参考にした。
接続用ユーザを作成する
ProxySQLからMySQLに接続するためのユーザを作成する。MySQLとProxySQLの両方でユーザ作成を行う必要がある。
# GroupReplicationのPrimaryノードで実行 mysql> CREATE USER 'proxysql'@'%' identified by 'password'; mysql> GRANT ALL ON *.* TO 'proxysql'@'%'; # ProxySQLの管理インターフェイスで実行 Admin> INSERT INTO mysql_users (username, password) VALUES ('proxysql', 'password'); Admin> LOAD MYSQL USERS TO RUNTIME; Admin> SAVE MYSQL USERS TO DISK;
接続ポートの設定を行う
ProxySQLの mysql-interfaces
の値を変更する。ProxySQLは大抵のパラメータを動的に変更可能だが、このパラメータに関しては再起動する必要がある。
Admin> SET mysql-interfaces='0.0.0.0:6401;0.0.0.0:6402'; Admin> SAVE MYSQL VARIABLES TO DISK; $ sudo service proxysql restart
ルーティングルールを設定する
6401ポートから接続された場合は書き込みグループへ、6402ポートから接続された場合は読み込みグループにルーティングするためのルールを設定する。
Admin> INSERT INTO mysql_query_rules (rule_id,active,proxy_port,destination_hostgroup,apply) VALUES (1,1,6401,1,1), (2,1,6402,2,1); Admin> LOAD MYSQL QUERY RULES TO RUNTIME; Admin> SAVE MYSQL QUERY RULES TO DISK;
これで、接続ポートによるR/W, R/O分割が可能。
試してみる
ProxySQLノード上で以下のコマンドを実行する。ちゃんと6401ポート→Primaryノード、6402ポート→Secondaryノードに接続できることが確認できる。
$ mysql -u proxysql -h 127.0.0.1 -P 6401 -p -BNe 'select @@hostname;' gr_primary $ mysql -u proxysql -h 127.0.0.1 -P 6402 -p -BNe 'select @@hostname;' gr_secondary2
2. 接続ユーザを分離する場合
接続ユーザを分離することによってR/W, R/O分割を行う。 R/W用ユーザはwriter、R/O用ユーザはreaderとした。
接続ユーザを作成する
ProxySQLからMySQLに接続するためのユーザを作成する。今回はwriterとreaderユーザを作成する。
# GroupReplicationのPrimaryノードで実行 mysql> CREATE USER 'writer'@'%' IDENTIFIED BY 'password'; mysql> GRANT ALL ON *.* TO 'writer'@'%'; mysql> CREATE USER 'reader'@'%' IDENTIFIED BY 'password'; mysql> GRANT ALL ON *.* TO 'reader'@'%'; # ProxySQLの管理インターフェイスで実行 Admin> INSERT INTO mysql_users (username, password, default_hostgroup) VALUES ('writer', 'password', 1), ('reader', 'password', 2); Admin> LOAD MYSQL USERS TO RUNTIME; Admin> SAVE MYSQL USERS TO DISK;
試してみる
ProxySQLノード上で以下のコマンドを実行する。ちゃんとwriterユーザ→Primaryノード、readerユーザ→Secondaryノードに接続できることが確認できる。(ProxySQLのデフォルトの接続ポートは6033)
$ mysql -u writer -h 127.0.0.1 -P 6033 -p -BNe 'select @@hostname;' gr_primary $ mysql -u reader -h 127.0.0.1 -P 6033 -p -BNe 'select @@hostname;' gr_secondary2
3. クエリの種類によって分離する場合
ProxySQLには正規表現によって一致したクエリを特定のグループへルーティングする機能がある。ProxySQL Wikiではこの方法が推奨されていそう。
接続ユーザを作成する
MySQLとProxySQLに接続ユーザを作成する。proxysql
ユーザは default_hostgroup
を1に設定し、全てのクエリをR/Wノード (Primaryノード) に向けておく。
mysql> CREATE USER 'proxysql'@'%' IDENTIFIED BY 'password'; mysql> GRANT ALL ON *.* TO 'proxysql'@'%'; Admin> INSERT INTO mysql_users (username, password, default_hostgroup) VALUES ('proxysql', 'password', 1); Admin> LOAD MYSQL USERS TO RUNTIME; Admin> SAVE MYSQL USERS TO DISK;
ルーティングルールを設定する
ProxySQL Wiki を参考にして、簡単なルーティングルールを設定してみる。
Admin> INSERT INTO mysql_query_rules (rule_id,active,match_digest,destination_hostgroup,apply) VALUES (1,1,'^SELECT.*FOR UPDATE$',1,1), (2,1,'^SELECT',2,1); Admin> LOAD MYSQL QUERY RULES TO RUNTIME; Admin> SAVE MYSQL QUERY RULES TO DISK;
この場合、SELECT ... FOR UPDATE
がR/Wノードに、それ以外のSELECT
がR/Oノードにルーティングされる。また、SELECT
以外で始まるすべてのクエリはデフォルトグループ (R/Wノード) にルーティングされる。
試してみる
ProxySQLノード上で以下のコマンドを実行する。SELECTから始まる場合は以下のようにSecondaryノードにルーティングされることが分かる。
$ mysql -u proxysql -h 127.0.0.1 -P 6033 -p -BNe 'select @@hostname;' gr_secondary1
ためしに、以下のようにtestデータベースを作成してみたところ、ちゃんとPrimaryノードにルーティングされたことが分かる。
$ mysql -u proxysql -h 127.0.0.1 -P 6033 -e 'create database test;' -p # Primaryノードで確認する mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | | test | +--------------------+
まとめ
ProxySQLを使ってInnoDB Clusterと同じように、アプリケーション側のフェイルオーバーができることが確認できた。ProxySQLはL7プロキシのため、かなり柔軟なルーティングが可能だったりする。ただし、その反面、管理しなければいけないものが増えるため、構成管理ツールとか導入しないと厳しいだろうなぁ、とか感じた。 もし、接続ポートをR/WとR/Oで分離したくないならば、MySQL Routerの代わりにProxySQLを使用するのも良いのかもしれない。
続・MySQL Routerの冗長化について
これはなに?
前の記事で Keepalived を用いたMySQL Routerの冗長化について書いたが、今回は Pacemaker + Corosync による冗長化について書こうと思う。
Keeplialivedの代わりに Pacemaker + Corosyncを使う以外は特に違いがないため InnoDB Clusterの構築までについては省略する。
構成
前回の記事と同じ構成。 Hyper-V上のUbuntu 18.04にLXCコンテナ (全てUbuntu 18.04) を立てて試してみた。
ノード | IPアドレス | ホスト名 |
---|---|---|
GroupReplication Primary | 10.0.3.11 | gr_primary |
GroupReplication Secondary1 | 10.0.3.12 | gr_secondary1 |
GroupReplication Secondary2 | 10.0.3.13 | gr_secondary2 |
MySQL Router Active | 10.0.3.21 | router_active |
MySQL Router Standby | 10.0.3.22 | router_standby |
MySQL Shell | 10.0.3.31 | mysql_shell |
Pacemaker + Corosync のインストール
MySQL Routerノード (10.0.3.21, 10.0.3.22) に必要なパッケージをインストールする。
$ sudo apt install pacemaker pcs resource-agents fence-agents
pcs
はPacemakerを管理するためのCLIで、従来のcrmsh
の代わりに使用することが推奨されている。
上記のパッケージをインストールすると、hacluster
というクラスタ用ユーザーが作成されるため、両方のノードで同じパスワードを設定しておく。
$ sudo passwd hacluster
そのあと、pcsdサービスを起動する。
$ sudo systemctl start pcsd $ sudo systemctl enable pcsd
クラスタの作成
クラスタ間通信を行うために名前解決ができる必要があるが、今回は内部DNSなどを設定していないため、MySQL Routerノードの /etc/hosts
ファイルに設定しておく。
$ cat /etc/hosts 10.0.3.21 router_active 10.0.3.22 router_standby
また、corosyncをインストールした段階で /etc/corosync/corosync.conf
が存在しているが、このファイルを削除しないと以下の手順が失敗するため事前に削除しておく。
$ sudo pcs cluster destroy # クラスタ構成ファイルが削除される $ sudo systemctl enable pacemaker # 上のコマンドによりpacemakerサービスが無効化されるため
pcs
コマンドを用いてクラスタを設定していく。以下はどちらか一方のノードでのみ実行する。しかし、pcs cluster start
を実行しようとすると以下のようなエラーメッセージを出して失敗する。
$ sudo pcs cluster auth router_active router_standby -u hacluster -p password $ sudo pcs cluster setup --name router_cluster router_active router_standby $ sudo pcs cluster start --all # ここで失敗する router_standby: Error connecting to router_standby - (HTTP error: 400) router_active: Error connecting to router_active - (HTTP error: 400) Error: unable to start all nodes router_standby: Error connecting to router_standby - (HTTP error: 400) router_active: Error connecting to router_active - (HTTP error: 400)
おそらく、以下のissueと同じ現象だと思う。
github.com
ローカルノードが異なるIPアドレスに解決してしまうのが原因らしい。
It turns out the whole issue was the local node resolving to a different IP internally. When that happens, commands return http code 400, but there are no logs that record what went wrong. Also, setting debug: on in the configuration doesn't make it output debug messages to the logs.
上記のissueと同じように、corosync.service
ファイルのType=notify
をType=simple
に変更して試してみても起動しなかったため、仕方がないので以下のようにホスト名の代わりにIPアドレスを使うことにした。
$ sudo pcs cluster auth 10.0.3.21 10.0.3.22 -u hacluster -p password $ sudo pcs cluster setup --name router_cluster 10.0.3.21 10.0.3.22 --force $ sudo pcs cluster start --all $ sudo pcs cluster enable --all
ちゃんと起動しているのが確認できる。
root@router_active:~# sudo pcs status 2 nodes configured 0 resources configured Online: [ router_active router_standby ] No resources
今回は検証目的なのでSTONITHは無効化しておく。また、2台構成のクラスタを組むのでquorumはignoreに設定しておく。
$ sudo pcs property set stonith-enabled=false $ sudo pcs property set no-quorum-policy=ignore
また、migration-threshold
も1に設定する。
$ sudo resource defaults migration-threshold=1
仮想IPリソースの作成
続いて、仮想IPリソースを作成する。今回は仮想IPとして 10.0.3.20 を割り当てることとする。また、モニタリング間隔は10秒ごととした。
$ sudo pcs resource create virtualip ocf:heartbeat:IPaddr2 ip=10.0.3.20 cidr_netmask=24 op monitor interval=10s
以下のようにvirtualipリソースが作成されているのを確認できる。
$ sudo pcs resource show virtualip Resource: virtualip (class=ocf provider=heartbeat type=IPaddr2) Attributes: cidr_netmask=24 ip=10.0.3.20 Operations: monitor interval=10s (virtualip-monitor-interval-10s) start interval=0s timeout=20s (virtualip-start-interval-0s) stop interval=0s timeout=20s (virtualip-stop-interval-0s)
MySQL Routerリソースの作成
次に、MySQL Routerをリソースとして追加する。
$ sudo pcs resource create mysqlrouter systemd:mysqlrouter clone
以下のようにmysqlrouterリソースが作成されているのが確認できる。
$ sudo pcs resource show mysqlrouter Resource: mysqlrouter (class=systemd type=mysqlrouter) Operations: monitor interval=60 timeout=100 (mysqlrouter-monitor-interval-60) start interval=0s timeout=100 (mysqlrouter-start-interval-0s) stop interval=0s timeout=100 (mysqlrouter-stop-interval-0s)
コロケーション制約を加える
作成した仮想IPリソースをMySQL Routerインスタンスに配置するために、INFINITYスコアを持つコロケーション制約を加える。
$ sudo pcs constraint colocation add virtualip with mysqlrouter-clone score=INFINITY
ちゃんと仮想IPが割り当てられていることが確認できる。
root@router_active:~# ip addr show 40: eth0@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:16:3e:5c:7a:63 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.3.21/24 brd 10.0.3.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.0.3.20/24 brd 10.0.3.255 scope global secondary eth0 valid_lft forever preferred_lft forever
障害テスト
あとは、MySQL Routerを止めたり、インスタンスを止めたりして仮想IPが入れ替わることを確認できれば終わり。
root@router_standby:~# ip addr show 46: eth0@if47: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:16:3e:ca:16:95 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.3.22/24 brd 10.0.3.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.0.3.20/24 brd 10.0.3.255 scope global secondary eth0 valid_lft forever preferred_lft forever
まとめ
KeepalivedとPacemaker + Corosyncで冗長構成を組んでみたが、個人的にはKeepalivedの方が分かりやすい気がした。昔はKeepalivedがMulticastにしか対応していなかったため、本番環境とかだと使いづらかったのかもしれないが、今は unicast_peer
とかでUnicastも対応できるっぽい。なので、Keepalivedを使うかPcacemaker + Corosyncを使うかは個人の好み次第で良いのかも?
MySQL Routerの冗長化について
これはなに?
本当はInnoDB Cluster構築の記事から始めようと思っていたけれど、もう素晴らしい記事が山ほどあって心を折られたので、差別化を図るためにMySQL Routerの冗長化手法について考えてみる。
具体的には Keepalived による冗長化手法を試してみた。
最終的な構成図は以下のような感じになる予定。 GroupReplicationはシングルプライマリモードで構築することにした。
2つのMySQL Routerで構成されたHAクラスタに1つの仮想IPを割り当てる構成。つまり、単純なActive-Stanby方式。もちろん2つ以上の仮想IPを割り当ててもよい (障害時に負荷に耐えられるなら) 。
ちなみに 公式ドキュメント には、アプリケーションサーバ上にMySQL Routerをインストールすることが推奨されているので、本記事は非推奨の方法であるということに注意。
For best performance, MySQL Router is typically installed on the same host as the application that uses it.
構成
Hyper-V上のUbuntu 18.04にLXCコンテナ (全てUbuntu 18.04) を立てて試してみた。
構成は以下のような感じ。バージョンはMySQL Server 8.0.19, MySQL Rotuer 8.0.19, MySQL Shell 8.0.19を使用した。
ノード | IPアドレス | ホスト名 |
---|---|---|
GroupReplication Primary | 10.0.3.11 | gr_primary |
GroupReplication Secondary1 | 10.0.3.12 | gr_secondary1 |
GroupReplication Secondary2 | 10.0.3.13 | gr_secondary2 |
MySQL Router Active | 10.0.3.21 | router_active |
MySQL Router Standby | 10.0.3.22 | router_standby |
MySQL Shell | 10.0.3.31 | mysql_shell |
my.cnfの設定
以下のような項目を /etc/mysql/my.cnf
に追記する。以下はPrimaryノードの設定。Secondaryノードは server_id
と report_host
の値をそれぞれ変更しておく。
[mysqld] server_id = 11 # 一意な値を設定 gtid_mode = on enforce_gtid_consistency = on binlog_checksum = none report_host = "10.0.3.11" # ホスト名解決ができない場合は必要 default_authentication_plugin = mysql_native_password
GroupReplicationの構築
MySQL Shellを使用してGroupReplicationを組んでいく。
まず、GroupReplicationを構築予定の各ノードでMySQL Shellからアクセス可能なユーザを作成しておく。ここでは簡単のために ALL
権限を付与した root
ユーザを作成する。
mysql> CREATE USER 'root'@'%' IDENTIFIED BY 'password'; mysql> GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION; mysql> reset master;
次に、MySQL Shellを使用してPrimaryノードに接続し、GroupReplicationを組む。
途中でCLONEプラグインを使用したりしたが、本題ではないので省略する。
$ mysqlsh MySQL JS> shell.connect('root@10.0.3.11') MySQL 10.0.3.11:33060+ ssl JS> cluster = dba.createCluster('test') MySQL 10.0.3.11:33060+ ssl JS> cluster.addInstance('root@10.0.3.12') MySQL 10.0.3.11:33060+ ssl JS> cluster.addInstance('root@10.0.3.13')
以下のようにGroupReplicationが構築できていることが確認できる。(cluster.status()
だと出力が長いので...)
MySQL 10.0.3.11:33060+ ssl JS> \sql MySQL 10.0.3.11:33060+ ssl SQL> select member_host, member_port, member_state, member_role, member_version from performance_schema.replication_group_members; +-------------+-------------+--------------+-------------+----------------+ | member_host | member_port | member_state | member_role | member_version | +-------------+-------------+--------------+-------------+----------------+ | 10.0.3.12 | 3306 | ONLINE | SECONDARY | 8.0.19 | | 10.0.3.13 | 3306 | ONLINE | SECONDARY | 8.0.19 | | 10.0.3.11 | 3306 | ONLINE | PRIMARY | 8.0.19 | +-------------+-------------+--------------+-------------+----------------+ 3 rows in set (0.0007 sec)
各ノードに mysql_innodb_cluster_metadata
スキーマが作成されているのを確認する。このスキーマがないと、MySQL RouterがGroupReplicationの状態を監視できないので重要。
ちなみに、MySQL Shellを使わずに手動で構築した場合、このスキーマが作成されないため、自分で作成するなどの対応が必要となる。(InnoDB Clusterの構成要素にMySQL RouterとGroupReplicationだけではなく、MySQL Shellも含まれている理由がこのスキーマの存在だと思う)。
mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | +-------------------------------+ 5 rows in set (0.01 sec)
MySQL Routerの設定
MySQL Routerをインストールした各ノードで以下のようにGroupReplicationに接続する。
$ sudo mysqlrouter --bootstrap root@10.0.3.11:3306 --user=mysqlrouter
すると、以下のようなコンフィグファイルが作成される。
bind_port
で指定されたポートにMySQL Clientで接続すると、destinations
で指定された対象ノードにルーティングを行ってくれる。(例えば、6446ポートに接続した場合は、Pirmaryノードにclassicプロトコルを用いて接続される)
destinations
が metadata-cache://test/?role=PRIMARY
のようになっていることから分かるように、MySQL RotuerはGroupReplicationのメタ情報を取得して動的にルーティングを行っている。(いままで, MySQL Router + MySQL Fabricで行っていたことが、MySQL Router + MySQL Shellに置き換えられたという感じだろうか)
$ cat /etc/mysqlrouter/mysqlrouter.conf # File automatically generated during MySQL Router bootstrap [DEFAULT] name=system user=mysqlrouter keyring_path=/run/mysqlrouter/keyring master_key_path=/etc/mysqlrouter/mysqlrouter.key connect_timeout=15 read_timeout=30 dynamic_state=/run/mysqlrouter/state.json [logger] level = INFO [metadata_cache:test] cluster_type=gr router_id=1 user=mysql_router1_hq01yshcvj7e metadata_cluster=test ttl=0.5 use_gr_notifications=0 [routing:test_rw] bind_address=0.0.0.0 bind_port=6446 destinations=metadata-cache://test/?role=PRIMARY routing_strategy=first-available protocol=classic [routing:test_ro] bind_address=0.0.0.0 bind_port=6447 destinations=metadata-cache://test/?role=SECONDARY routing_strategy=round-robin-with-fallback protocol=classic [routing:test_x_rw] bind_address=0.0.0.0 bind_port=64460 destinations=metadata-cache://test/?role=PRIMARY routing_strategy=first-available protocol=x [routing:test_x_ro] bind_address=0.0.0.0 bind_port=64470 destinations=metadata-cache://test/?role=SECONDARY routing_strategy=round-robin-with-fallback protocol=x
MySQL ServerにもMySQL Router用のユーザが作成されているのが確認できる。
mysql> select user,host from mysql.user; +----------------------------+-----------+ | user | host | +----------------------------+-----------+ | mysql_innodb_cluster_11 | % | | mysql_innodb_cluster_12 | % | | mysql_innodb_cluster_13 | % | | mysql_router1_hq01yshcvj7e | % | | mysql_router2_xswvvfihkzr4 | % | | root | % | | mysql.infoschema | localhost | | mysql.session | localhost | | mysql.sys | localhost | | root | localhost | +----------------------------+-----------+
MySQL Shellノード (10.0.3.31) から接続して、ちゃんとルーティングされていることを確認しておく。
root@mysql_shell:~# mysqlsh --sql root@10.0.3.21:6446 -p -e 'select @@hostname;' @@hostname gr_primary root@mysql_shell:~# mysqlsh --sql root@10.0.3.22:6446 -p -e 'select @@hostname;' @@hostname gr_primary
Keepalivedの設定
MySQL Routerを冗長化するためにKeepalivedの設定をおこなっていく。
MySQL Routerノード (10.0.3.21, 10.0.3.22) にKeepalivedをインストールし、設定ファイル (/etc/keepalived/keepalived.conf
) に以下のような設定を行う。各パラメータの詳細は他の記事や 公式ドキュメント を参考に。
$ cat /etc/keepalived/keepalived.conf vrrp_script chk_mysqlrouter { script "/usr/bin/killall -0 /usr/bin/mysqlrouter" # mysqlrouterのプロセスを監視する interval 2 fall 2 } vrrp_instance VI_1 { interface eth0 state BACKUP # Active, StandbyともにBACKUPとした virtual_router_id 51 priority 101 # Activeノードは101, Standbyノードは100に設定した advert_int 1 nopreempt virtual_ipaddress { 10.0.3.20/24 # 仮想IPとして10.0.3.20を使用する } track_script { chk_mysqlrouter } }
Activeノード (10.0.3.21) に、仮想IP (10.0.3.20) が割り当てられていることが確認できる。
root@router_active:~# ip addr show eth0 18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:16:3e:a6:b9:dd brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.3.21/24 brd 10.0.3.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.0.3.20/24 scope global secondary eth0 valid_lft forever preferred_lft forever
MySQL Shellノードから仮想IPに対して接続して、ちゃんとルーティングが行われていることを確認する。
root@mysql_shell:~# mysqlsh --sql root@10.0.3.20:6446 -p -e 'select @@hostname;' @@hostname gr_primary root@mysql_shell:~# mysqlsh --sql root@10.0.3.20:6447 -p -e 'select @@hostname;' @@hostname gr_secondary2
これでKeepalivedを用いたMySQL Routerの冗長化が完成。
障害テスト
最後に、Activeノードに障害が発生し、MySQL Routerが停止した場合でもちゃんと問題なく動作するかを検証する。シナリオは以下のような感じ。
まず、ActiveノードのMySQL Routerを停止する。
root@router_active:~# sudo service mysqlrouter stop
仮想IP (10.0.3.20) が Standbyノード (10.0.3.22) に切り替わっているのが確認できる。
root@router_standby:~# ip addr show eth0 20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 00:16:3e:12:55:6f brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.0.3.22/24 brd 10.0.3.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.0.3.20/24 scope global secondary eth0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe12:556f/64 scope link valid_lft forever preferred_lft forever
障害後も、仮想IP経由で障害前と同じようにGroupReplicationに接続できることが確認できる。
root@mysql_shell:~# mysqlsh --sql root@10.0.3.20:6446 -p -e 'select @@hostname;' @@hostname gr_primary root@mysql_shell:~# mysqlsh --sql root@10.0.3.20:6447 -p -e 'select @@hostname;' @@hostname gr_secondary2
おわりに
学んだことのアウトプットとしてブログをはじめてみたけど、記事を書くのってめちゃくちゃ大変。。。
はたしてこれからも続けられるのか。。。