MySQLのHAのためにMySQL Group Replication + MySQL InnoDB Cluster環境を構築
2017年4月12日に早くもGAになったMySQL InnoDB Cluster を早速使ってみました。
Vagrant で立てた MySQL Group Replication 3台 (mysql-node1~mysql-node3)
+ Webサーバー1台(mysql-web) の環境でテストしています。
構築概要
- Vagrant上でMySQL Group Replication 3台(MySQL 5.7)を構築し、
WebサーバーにMySQL Router、MySQL Shell、MySQL-clientをインストールします。 - 今回のGroup Replication環境ではシングルプライマリモードを適用します。
- Group Replication 構築完了後、 WebサーバーでMySQL Shell を操作して、InnoDB Clusterを登録します。
- 最終目標としてMySQL Router + MySQL Shell 環境から
MySQL InnoDB Clusterへの接続テスト及びフェイルオーバーテストを行います。
構築手順
0.環境
- CentOS 6.9
- MySQL5.7
- MySQL Router 2.1
- MySQL Shell 1.0
- MySQL Client 5.7
1.MySQLサーバー構築
以下のVagrantfileを利用して下記の4サーバーをVagrant上で構築します。
- mysql-node1:192.168.40.10
- mysql-node2:192.168.40.20
- mysql-node3:192.168.40.30
- mysql-web:192.168.40.100
- Vagrantfile
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 31 32 33 34 35 36 37 38 39 |
# -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure(2) do |config| config.vm.synced_folder ".", "/vagrant", type:"virtualbox" if Vagrant.has_plugin?("vagrant-timezone") config.timezone.value = "Asia/Tokyo" end config.vm.define "node1" do |node| node.vm.box = "centos/6" node.vm.hostname = "mysql-node1" node.vm.network :private_network, ip: "192.168.40.10" end config.vm.define "node2" do |node| node.vm.box = "centos/6" node.vm.hostname = "mysql-node2" node.vm.network :private_network, ip: "192.168.40.20" end config.vm.define "node3" do |node| node.vm.box = "centos/6" node.vm.hostname = "mysql-node3" node.vm.network :private_network, ip: "192.168.40.30" end config.vm.define "web" do |node| node.vm.box = "centos/6" node.vm.hostname = "mysql-web" node.vm.network :private_network, ip: "192.168.40.100" end end |
※vagrant-vbguest / vagrant-timezone プラグインを入れています。
- 全サーバー間で名前解決できるように以下の内容を全サーバーの/etc/hostsファイルに追記します。
1 2 3 4 |
192.168.40.10 mysql-node1 192.168.40.20 mysql-node2 192.168.40.30 mysql-node3 192.168.40.100 mysql-web |
- 全ノードにおいてselinux、iptables、ip6tablesを一時的にオフにします。
1 2 3 |
# setenforce 0 # service iptables stop # service ip6tables stop |
2.MySQL5.7、MySQL Router 2.1、MySQL Shell 1.0 の最新版をインストール
※インストール先は以下の通りです。
- mysql-node1~3:MySQL5.7
- mysql-web:MySQL Router 2.1、MySQL Shell 1.0、MySQL-client
- MySQL5.7 のインストール
(1)以下のコマンドを実行しrpmパッケージをインストールします。
1 |
node# yum install http://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm |
※2017/5/30時点の最新版はmysql57-community-release-el6-11.noarch.rpmです。
(2)インストールしたrpmパッケージを
node1~node3のそれぞれの/tmp/配下に配置します。
(3)以下のコマンドを実行しMySQLをインストールします。
1 2 |
node1# yum remove -y mysql-libs node1# yum install -y mysql-server |
1 2 3 4 5 6 |
Installed: mysql-community-server.x86_64 0:5.7.18-1.el6 Dependency Installed: mysql-community-client.x86_64 0:5.7.18-1.el6 mysql-community-common.x86_64 0:5.7.18-1.el6 mysql-community-libs.x86_64 0:5.7.18-1.el6 |
※同じ処理をnode2とnode3にも実行します。
- MySQL Router のインストール
以下のコマンドを実行しMySQL Router をインストールします。
1 2 |
web# yum install -y mysql57-community-release-el6-11.noarch.rpm web# yum install -y mysql-router |
1 2 |
Installed: mysql-router.x86_64 0:2.1.3-1.el6 |
- MySQL Shell のインストール
以下のコマンドを実行しMySQL Shell をインストールします。
1 |
web# yum install -y mysql-shell |
1 2 |
Installed: mysql-shell.x86_64 0:1.0.9-1.el6 |
- MySQL client のインストール
以下のコマンドを実行しMySQL client をインストールします。
1 |
web# yum install -y mysql-community-client |
1 2 3 4 |
Installed: mysql-community-client.x86_64 0:5.7.18-1.el6 mysql-community-libs.x86_64 0:5.7.18-1.el6 mysql-community-libs-compat.x86_64 0:5.7.18-1.el6 |
3.MySQL Group Replicationの構築
(1)下記の"node1_my.cnf"、"node2_my.cnf"、"node3_my.cnf"を、
それぞれのnodeの/tmp/配下に配置します。
- node1_my.cnf
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 |
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 skip_name_resolve innodb_buffer_pool_size = 128M # For Replication server_id=10 ### change in Node2 and Node3 gtid_mode=ON enforce_gtid_consistency=ON master_info_repository=TABLE relay_log_info_repository=TABLE binlog_checksum=NONE log_slave_updates=ON log_bin=binlog binlog_format=ROW relay-log=relaylog # For Group Replication transaction_write_set_extraction=XXHASH64 loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" loose-group_replication_start_on_boot=off loose-group_replication_local_address="192.168.40.10:24901" ### change in Node2 and Node3 loose-group_replication_group_seeds="192.168.40.10:24901,192.168.40.20:24902,192.168.40.30:24903" loose-group_replication_bootstrap_group=off log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid |
- node2_my.cnf
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 |
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 skip_name_resolve innodb_buffer_pool_size = 128M # For Replication server_id=20 ### change in Node2 and Node3 gtid_mode=ON enforce_gtid_consistency=ON master_info_repository=TABLE relay_log_info_repository=TABLE binlog_checksum=NONE log_slave_updates=ON log_bin=binlog binlog_format=ROW relay-log=relaylog # For Group Replication transaction_write_set_extraction=XXHASH64 loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" loose-group_replication_start_on_boot=off loose-group_replication_local_address="192.168.40.20:24902" ### change in Node2 and Node3 loose-group_replication_group_seeds="192.168.40.10:24901,192.168.40.20:24902,192.168.40.30:24903" loose-group_replication_bootstrap_group=off log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid |
- node3_my.cnf
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 |
[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 skip_name_resolve innodb_buffer_pool_size = 128M # For Replication server_id=30 ### change in Node2 and Node3 gtid_mode=ON enforce_gtid_consistency=ON master_info_repository=TABLE relay_log_info_repository=TABLE binlog_checksum=NONE log_slave_updates=ON log_bin=binlog binlog_format=ROW relay-log=relaylog # For Group Replication transaction_write_set_extraction=XXHASH64 loose-group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" loose-group_replication_start_on_boot=off loose-group_replication_local_address="192.168.40.30:24903" ### change in Node2 and Node3 loose-group_replication_group_seeds="192.168.40.10:24901,192.168.40.20:24902,192.168.40.30:24903" loose-group_replication_bootstrap_group=off log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid |
(2)以下のコマンドで各nodeに配置したmy.cnfを/etc/my.cnfに上書きします。
1 2 3 |
node1# cp /tmp/node1_my.cnf /etc/my.cnf node2# cp /tmp/node2_my.cnf /etc/my.cnf node3# cp /tmp/node3_my.cnf /etc/my.cnf |
(3)以下のコマンドで各nodeにてmysqldを起動します。
1 2 3 |
node1# service mysqld start node2# service mysqld start node3# service mysqld start |
(4)簡単なパスワードを使用するため、
各nodeのvalidate_pluginをアンインストールします。
- 以下のコマンドで作成される一時的なrootユーザーのパスワードでMySQLにログインします。
1 2 |
node1# cat /var/log/mysqld.log | grep temporary node1# mysql -u root -p |
- varidate_pluginをアンインストールした後、パスワードを再設定します。
1 2 3 |
mysql> SET PASSWORD = "MySQL_5.7"; mysql> UNINSTALL PLUGIN validate_password; mysql> SET PASSWORD = "password"; |
(5)Group Replication Pluginの有効化、ユーザーの作成を行います。
1 2 3 4 5 6 |
mysql> INSTALL PLUGIN group_replication SONAME 'group_replication.so'; mysql> SET SQL_LOG_BIN=0; mysql> CREATE USER rpl_user@'%'; mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%' IDENTIFIED BY 'rpl_pass'; mysql> SET SQL_LOG_BIN=1; mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='rpl_pass' FOR CHANNEL 'group_replication_recovery'; |
※上記の(4),(5)と同じ処理をnode2とnode3にも実行します。
(6)初期ノード(node1)を起動します。
1 2 3 |
mysql> SET GLOBAL group_replication_bootstrap_group=ON; mysql> START GROUP_REPLICATION; mysql> SET GLOBAL group_replication_bootstrap_group=OFF; |
(7)第2ノード(node2)を起動します。
1 2 |
mysql> RESET MASTER; mysql> START GROUP_REPLICATION; |
(8)第3ノード(node3)を起動し、Group Replication情報を参照します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
mysql> RESET MASTER; mysql> START GROUP_REPLICATION; mysql> SELECT * FROM performance_schema.replication_group_members\G *************************** 1. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 10f9e03c-2be9-11e7-9545-5254008a28ff MEMBER_HOST: mysql-node3 MEMBER_PORT: 3306 MEMBER_STATE: ONLINE *************************** 2. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: 7ca04fe0-2be8-11e7-905d-5254008a28ff MEMBER_HOST: mysql-node2 MEMBER_PORT: 3306 MEMBER_STATE: ONLINE *************************** 3. row *************************** CHANNEL_NAME: group_replication_applier MEMBER_ID: a51a10dc-2be7-11e7-88cd-5254008a28ff MEMBER_HOST: mysql-node1 MEMBER_PORT: 3306 MEMBER_STATE: ONLINE 3 rows in set (0.00 sec) |
(9)初期ノードにてwebサーバーからアクセスするためのappユーザーを作成します。
1 |
mysql> GRANT ALL ON *.* TO <code>app</code>@<code>192.168.40.100</code> IDENTIFIED BY "app_pass" WITH GRANT OPTION; |
※MySQL Shellがクラスタを作成するために、"WITH GRANT OPTION"権限が必要です。
4.webサーバーで、MySQL Shell を操作して、クラスタを登録
※以下の操作はrootユーザーを使用しません。
- node1に接続し、InnoDB Clusterを新規作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
web$ mysqlsh mysql-js> shell.connect("app@192.168.40.10:3306"); Please provide the password for 'app@192.168.40.10:3306': Creating a Session to 'app@192.168.40.10:3306' Classic Session successfully established. No default schema selected. mysql-js> var cluster = dba.createCluster('test_innodb_cluster', {adoptFromGR: true}); A new InnoDB cluster will be created on instance 'app@192.168.40.10:3306'. Creating InnoDB cluster 'test_innodb_cluster' on 'app@192.168.40.10:3306'... Adding Seed Instance... Cluster successfully created. Use Cluster.addInstance() to add MySQL instances. At least 3 instances are needed for the cluster to be able to withstand up to one server failure. |
- Clusterが問題なく登録されたことを確認します。
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
mysql-js> cluster.describe(); { "clusterName": "test_innodb_cluster", "defaultReplicaSet": { "instances": [ { "host": "192.168.40.10:3306", "label": "192.168.40.10:3306", "role": "HA" }, { "host": "mysql-node3:3306", "label": "mysql-node3:3306", "role": "HA" }, { "host": "mysql-node2:3306", "label": "mysql-node2:3306", "role": "HA" } ], "name": "default" } } mysql-js> cluster.status(); { "clusterName": "test_innodb_cluster", "defaultReplicaSet": { "name": "default", "primary": "192.168.40.10:3306", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "192.168.40.10:3306": { "address": "192.168.40.10:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "mysql-node2:3306": { "address": "mysql-node2:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "mysql-node3:3306": { "address": "mysql-node3:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" } } } } |
※node1がPrimary nodeとして設定されています。
5.MySQL Routerで InnoDB Clusterに接続する
- 以下のコマンドでInnoDB Cluster に接続します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
web$ sudo su - web# mysqlrouter --bootstrap app@192.168.40.10:3306 --user=mysqlrouter Please enter MySQL password for app: Bootstrapping system MySQL Router instance... MySQL Router has now been configured for the InnoDB cluster 'test_innodb_cluster'. The following connection information can be used to connect to the cluster. Classic MySQL protocol connections to cluster 'test_innodb_cluster': - Read/Write Connections: localhost:6446 - Read/Only Connections: localhost:6447 X protocol connections to cluster 'test_innodb_cluster': - Read/Write Connections: localhost:64460 - Read/Only Connections: localhost:64470 Existing configurations backed up to /etc/mysqlrouter/mysqlrouter.conf.bak |
- 上記の操作でnode1~3のMySQL上に
“mysql_innodb_cluster_metadata” というスキーマが作成されます。
1 2 3 4 5 6 7 8 9 10 11 |
mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | +-------------------------------+ 5 rows in set (0.00 sec) |
- 新規作成されたスキーマが確認できたら、MySQL Routerを起動します。
1 2 3 |
web# chown mysqlrouter:mysqlrouter /var/lib/mysqlrouter web# mysqlrouter & [1] 3057 |
※/var/lib/mysqlrouterの権限が"root:root"になっているため、chownを実行します。
6. MySQL Router + MySQL Shell環境からInnoDB Clusterへの接続テスト及びフェイルオーバーテスト
- Read/Writeの接続(6446ポート指定)を行います。
1 2 3 4 5 6 7 |
web# mysql -u app -papp_pass -h 127.0.0.1 -P 6446 -e "select @@hostname" mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node1 | +-------------+ |
⇒全てnode1に対してのみ実行されます。
- Read Onlyの接続(6447ポート指定)を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
web# mysql -u app -papp_pass -h 127.0.0.1 -P 6447 -e "select @@hostname" mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node3 | +-------------+ web# mysql -u app -papp_pass -h 127.0.0.1 -P 6447 -e "select @@hostname" mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node2 | +-------------+ |
⇒node2 と node3 に対して、ラウンドロビンで実行されます。
- フェイルオーバーテストを行います。
(1)以下のコマンドをnode1に対しクエリを実行します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
web# for i in {0..29} >do >mysql -u app -papp_pass -h 127.0.0.1 -P 6446 -e "select @@hostname" >sleep 1 >done mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node1 | +-------------+ mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node1 | +-------------+ |
(2)上記のコマンド実行中に、node1をダウンさせます。
1 |
node1# service mysqld stop |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
web# mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node1 | +-------------+ mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node1 | +-------------+ mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node3 | +-------------+ |
⇒6446ポートの参照先がnode1からnode3に切り替わります。(フェイルオーバー)
※その後は、node1を起動させても6446ポートの参照先はnode3のままとなります。
1 2 3 4 5 6 7 |
web# mysql -u app -papp_pass -h 127.0.0.1 -P 6446 -e "select @@hostname" mysql: [Warning] Using a password on the command line interface can be insecure. +-------------+ | @@hostname | +-------------+ | mysql-node3 | +-------------+ |
⇒Primary node がnode3に切り替わります。
構築してみた感想
今回はMySQL Group Replication、MySQL Router、MySQL Shellを組み合わせて
高可用性を実現できるMySQL InnoDB Clusterを構築してみましたが、
管理リポジトリ自体がGroup Replication内にありますのでデフォルトでデータベースが冗長化されています。
また、MySQL Group Replication、MySQL Router、MySQL Shellが密に連携していて一つのHAパッケージのようになっていると感じました。
構築手順自体は難しいものではなく、Primary nodeがダウンした場合に自動的にSecondary nodeにフェイルオーバーが可能であり、かつダウンしたサーバーが復旧した場合も自動的にクラスタに再加入できますので有用性の高いものだと考えています。
参考URL
Chapter 20 InnoDB Cluster