MySQL 5.7.23 のGroup Replicationでデータに差分がある状態での復旧を確認
前回はデータ更新が無い状態でNodeの復旧について確認しました。 今回はデータ更新がある状態でのNode復旧について確認します。
確認項目は以下です。
- すべてのNodeがONLINE状態でデータを追加してSecondary Nodeで見れるか
- Secondary Nodeでデータ追加ができないか
- Secondary Nodeを止めた状態でデータを更新系query(insert update delete)を走らせて、Nodeを復旧してちゃんと更新されるか
- Primary Nodeで更新系queryを走らせた後、同期が完了する前にPrimary Nodeを停止させて、Primary Nodeが切り替わった後に旧Primary Nodeを復旧させてみてデータが同期されるか
- binlogを意図的に欠損させてみる
結論としては、binlogの欠損がなければそのうち同期される。
欠損があれば、Master-Slave Replicationと同様にdumpとって復旧する必要がある。
という感じでした。
すべてのNodeがONLINE状態でデータを追加してSecondary Nodeで見れるか
これは問題ないでしょうが確認しておきましょう。
Primary Nodeであるnode1でデータを追加します。
[node1] $ sudo mysql -u root mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | +-------------------------------+ 5 rows in set (0.00 sec) mysql> CREATE DATABASE test; Query OK, 1 row affected (0.00 sec) mysql> CREATE TABLE test.t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL); Query OK, 0 rows affected (0.03 sec) mysql> INSERT INTO test.t1 VALUES (1, 'Yui'); Query OK, 1 row affected (0.01 sec)
Secondary Nodeであるnode2でデータを確認してみましょう。
同期できているようですね。
[node2] $ sudo mysql -u root mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | | test | +-------------------------------+ 6 rows in set (0.00 sec) mysql> show tables from test; +----------------+ | Tables_in_test | +----------------+ | t1 | +----------------+ 1 row in set (0.00 sec) mysql> select * from test.t1; +----+------+ | c1 | c2 | +----+------+ | 1 | Yui | +----+------+ 1 row in set (0.00 sec)
Secondary Nodeでデータ追加ができないか
これもできていて当たり前ですが確認してみましょう。
Secondary Nodeではsuper read only modeがONになっているので実行できませんね。
[node2] $ sudo mysql -u root mysql> CREATE DATABASE hoge; ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option so it cannot execute this statement
試しにOFFにしてみましょう。
追加できちゃいましたね?
mysql> set global super_read_only=off; Query OK, 0 rows affected (0.00 sec) mysql> CREATE DATABASE hoge; Query OK, 1 row affected (0.01 sec)
他のNodeでも同期されているのでしょうか。
されちゃってますねー。
[node1] $ sudo mysql -u root mysql> show databases; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | hoge | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | sys | | test | +-------------------------------+ 7 rows in set (0.00 sec)
Group Replicationのstatus的にはどうなんでしょうか。
実質Multi Primary Modeですがstatus的にはnode1のみRead/WriteでSingle Primary Modeのままですね。
[node1] $ mysqlsh --log-level=DEBUG3 --uri repl@node1:3306 MySQL node1:3306 JS > var cluster = dba.createCluster('myCluster') MySQL node1:3306 JS > cluster.status() { "clusterName": "myCluster", "defaultReplicaSet": { "name": "default", "primary": "node1:3306", "ssl": "DISABLED", "status": "OK_NO_TOLERANCE", "statusText": "Cluster is NOT tolerant to any failures.", "topology": { "node1:3306": { "address": "node1:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "node2:3306": { "address": "node2:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "node3:3306": { "address": "node3:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" } }, "topologyMode": "Single-Primary" }, "groupInformationSourceMember": "node1:3306" }
どんな問題が起こるか分からないので、super-read-onlyはONのままにしておきましょう。
Secondary Nodeを止めた状態でデータを更新系query(insert update delete)を走らせて、Nodeを復旧してちゃんと更新されるか
これもできてほしいですが試してみましょう。
INSERTのみ
まずは、insertのみを実行します。はい、余裕でできますね。
[node2] $ sudo systemctl stop mysqld [node1] $ sudo mysql -u root mysql> CREATE DATABASE poge; CREATE TABLE poge.t1 (c1 INT PRIMARY KEY, c2 TEXT NOT NULL); INSERT INTO poge.t1 VALUES (1, 'Ogura'); Query OK, 1 row affected (0.01 sec) Query OK, 0 rows affected (0.03 sec) Query OK, 1 row affected (0.01 sec) [node2] $ sudo systemctl start mysqld; sudo mysql -u root mysql> SHOW DATABASES; show tables from poge; select * from poge.t1; +-------------------------------+ | Database | +-------------------------------+ | information_schema | | hoge | | mysql | | mysql_innodb_cluster_metadata | | performance_schema | | poge | | sys | | test | +-------------------------------+ 8 rows in set (0.00 sec) +----------------+ | Tables_in_poge | +----------------+ | t1 | +----------------+ 1 row in set (0.00 sec) +----+-------+ | c1 | c2 | +----+-------+ | 1 | Ogura | +----+-------+ 1 row in set (0.00 sec)
UPDATEのみ
mysqlプロセス再起動後すぐにselectすると更新されていませんでしたが、再実行すると更新されていました。
[node2] $ sudo systemctl stop mysqld [node1] $ sudo mysql -u root -e "UPDATE poge.t1 SET c2=Rina WHERE c1=1;" [node2] $ sudo systemctl start mysqld; sudo mysql -u root -e "select * from poge.t1;" +----+-------+ | c1 | c2 | +----+-------+ | 1 | Ogura | +----+-------+ [node2] $ sudo mysql -u root -e "select * from poge.t1;" +----+------+ | c1 | c2 | +----+------+ | 1 | Rina | +----+------+
DELETEのみ
これも問題ないですね
[node2] $ sudo systemctl stop mysqld [node1] $ sudo mysql -u root -e "DELETE FROM poge.t1 WHERE c1=1; SELECT * FROM poge.t1;" [node2] $ sudo systemctl start mysqld; sudo mysql -u root -e "SELECT * FROM poge.t1;" +----+------+ | c1 | c2 | +----+------+ | 1 | Rina | +----+------+ [node2] $ sudo mysql -u root -e "SELECT * FROM poge.t1;"
INSERT, UPDATE, DELETEまとめて
ある程度データを入れた状態で試してみましょう。
多少遅れますがまあ問題無いですね。
[node1] $ sudo mysql -u root mysql> INSERT INTO poge.t1 VALUES (2, 'Hidaka'), (3, 'Sakura'), (4, 'Ayane'), (5, 'Serizawa'), (6, 'Yu'), (7, 'Uchida'), (8, 'Maya'), (9, 'Minase'), (10, 'Inori'); Query OK, 9 rows affected (0.02 sec) Records: 9 Duplicates: 0 Warnings: 0 mysql> SELECT * FROM poge.t1; +----+----------+ | c1 | c2 | +----+----------+ | 2 | Hidaka | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 7 | Uchida | | 8 | Maya | | 9 | Minase | | 10 | Inori | +----+----------+ 9 rows in set (0.00 sec) [node2] $ sudo mysql -u root -e "SELECT * FROM poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ | 2 | Hidaka | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 7 | Uchida | | 8 | Maya | | 9 | Minase | | 10 | Inori | +----+----------+ 9 rows in set (0.00 sec) [node2] $ sudo systemctl stop mysqld [node1] $ sudo mysql -u root -e "DELETE FROM poge.t1 WHERE c1=7; UPDATE poge.t1 SET c2='Rina' WHERE c1=2; INSERT INTO poge.t1 VALUES (11, 'Ogura'), (12, 'Yui'); SELECT * FROM poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ | 2 | Rina | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 8 | Maya | | 9 | Minase | | 10 | Inori | | 11 | Ogura | | 12 | Yui | +----+----------+ [node2] $ sudo systemctl start mysqld; sudo mysql -u root -e "SELECT * FROM poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ | 2 | Hidaka | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 7 | Uchida | | 8 | Maya | | 9 | Minase | | 10 | Inori | +----+----------+ [node2] $ sudo mysql -u root -e "SELECT * FROM poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ | 2 | Hidaka | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 7 | Uchida | | 8 | Maya | | 9 | Minase | | 10 | Inori | +----+----------+ [node2] $ sudo mysql -u root -e "SELECT * FROM poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ | 2 | Rina | | 3 | Sakura | | 4 | Ayane | | 5 | Serizawa | | 6 | Yu | | 8 | Maya | | 9 | Minase | | 10 | Inori | | 11 | Ogura | | 12 | Yui |
Primary Nodeで更新系queryを走らせた後、同期が完了する前にPrimary Nodeを停止させて、Primary Nodeが切り替わった後に旧Primary Nodeを復旧させてみてデータが同期されるか
どう試そうか迷いますが以下の流れで実行してみます。
- 処理1
- session1でPrimary Nodeにupdate文を流しまくる。
- session1の処理が完了する前にsession2でPrimary Nodeのmysqldをkill。
- 処理2
- 旧Primary Nodeで最後に実行できたqueryが新Primary Nodeで反映されているかどうか確認。
- 処理3
- 旧Primary Nodeのmysqldを再起動。
- 処理4
- 旧Primary Nodeのデータと新Primary Nodeのデータを確認。
処理1
Primary Nodeでこのscriptを実行しつつkillします。
#! /bin/env bash i=15 while : do sudo mysql -u root -e "INSERT INTO poge.t1 VALUES ($i, 'Ogura$i');" i=`expr $i + 1` done
session1で実行しつつ、session2でkillします。
[node1] $ sudo ./while.sh ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104 ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (111) ... ERROR 1290 (HY000) at line 1: The MySQL server is running with the --super-read-only option so it cannot execute this statement ERROR 1290 (HY000) at line 1: The MySQL server is running with the --super-read-only option so it cannot execute this statement ...
[node1] $ ps aux | grep mysql mysql 25083 0.3 9.1 10590220 1058624 ? Sl 11:28 1:03 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid [node1] $ kill -9 25083
killしたタイミングでコネクションが貼れなくなりエラーが出ていますが、少し経つとsuper-read-onlyなので実行できないよエラーに変わります。
systemdがmysqlプロセスを再起動したみたいですね。
データを確認してみましょう。
旧Primary Node(node1)と新Primary Node(node2)で一致していました。
[node1] $ sudo mysql -u root -e "select * from poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ ... | 79 | Ogura79 | +----+----------+ [node2] $ sudo mysql -u root -e "select * from poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ ... | 79 | Ogura79 | +----+----------+
Group Replicationの状態としては、node1がMissing(本人にとってはOFFLINE)になっていました。
[node2] $ mysqlsh --log-level=DEBUG3 --uri repl@node2:3306 MySQL node2:3306 JS > var cluster = dba.getCluster() MySQL node2:3306 JS > cluster.status() { "clusterName": "myCluster", "defaultReplicaSet": { "name": "default", "primary": "node1:3306", "ssl": "DISABLED", "status": "OK_NO_TOLERANCE", "statusText": "Cluster is NOT tolerant to any failures. 1 member is not active", "topology": { "node1:3306": { "address": "node1:3306", "mode": "n/a", "readReplicas": {}, "role": "HA", "status": "(MISSING)" }, "node2:3306": { "address": "node2:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "node3:3306": { "address": "node3:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" } }, "topologyMode": "Single-Primary" }, "groupInformationSourceMember": "node2:3306" } [node1] $ sudo mysql -u root -e "SELECT * from performance_schema.replication_group_members ORDER BY MEMBER_HOST;" +---------------------------+--------------------------------------+--------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ | group_replication_applier | 440dd2c5-a22b-11e9-b851-fa163e47fb1b | node1 | 3306 | OFFLINE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ 1 row in set (0.00 sec) [node2] $ sudo mysql -u root -e "SELECT * from performance_schema.replication_group_members ORDER BY MEMBER_HOST;" +---------------------------+--------------------------------------+--------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ | group_replication_applier | 34ce3aed-a249-11e9-b3e8-fa163e4531c6 | node2 | 3306 | ONLINE | | group_replication_applier | d46d27c7-a24e-11e9-a4e6-fa163e4b9377 | node3 | 3306 | ONLINE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ 2 row in set (0.00 sec)
node1でSTART GROUP_REPLICATION;
してみます。
ONLINEになりました。
systemdがmysqlを自動復旧したときにSTART GROUP_REPLICATION;
が実行されないのかな?
[node1] $ sudo mysql -u root -e "START GROUP_REPLICATION;" [node2] $ sudo mysql -u root -e "SELECT * from performance_schema.replication_group_members ORDER BY MEMBER_HOST;" +---------------------------+--------------------------------------+--------------+-------------+--------------+ | CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ | group_replication_applier | 440dd2c5-a22b-11e9-b851-fa163e47fb1b | node1 | 3306 | ONLINE | | group_replication_applier | 34ce3aed-a249-11e9-b3e8-fa163e4531c6 | node2 | 3306 | ONLINE | | group_replication_applier | d46d27c7-a24e-11e9-a4e6-fa163e4b9377 | node3 | 3306 | ONLINE | +---------------------------+--------------------------------------+--------------+-------------+--------------+ [node2] $ mysqlsh --log-level=DEBUG3 --uri repl@node2:3306 MySQL node2:3306 JS > var cluster = dba.getCluster() MySQL node2:3306 JS > cluster.status() { "clusterName": "myCluster", "defaultReplicaSet": { "name": "default", "primary": "node1:3306", "ssl": "DISABLED", "status": "OK", "statusText": "Cluster is ONLINE and can tolerate up to ONE failure.", "topology": { "node1:3306": { "address": "node1:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "node2:3306": { "address": "node2:3306", "mode": "R/W", "readReplicas": {}, "role": "HA", "status": "ONLINE" }, "node3:3306": { "address": "node3:3306", "mode": "R/O", "readReplicas": {}, "role": "HA", "status": "ONLINE" } }, "topologyMode": "Single-Primary" }, "groupInformationSourceMember": "node2:3306" }
処理1 systemdでやり直し
mysqlが想定外の挙動になってしまったので、systemdでやり直してみます。
#! /bin/env bash i=100 while : do sudo mysql -u root -e "INSERT INTO poge.t1 VALUES ($i, 'Ogura$i');" i=`expr $i + 1` done
session1で実行しつつ、session2でkillします。
[node2] $ sudo ./while.sh ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) ...
[node2] $ sudo systemctl stop mysqld
無事停止されました。
処理2
旧Primary Nodeで最後に実行できたqueryを確認できてないのですが、
新Primary Nodeを確認してみましょう。
160まで追加されていますね。
[node1] $ sudo mysql -u root -e "select * from poge.t1;" +----+----------+ | c1 | c2 | +----+----------+ ... | 160 | Ogura160 | +-----+----------+ 136 rows in set (0.00 sec)
処理3
旧Primary Nodeのmysqldを再起動してみます。
無事起動してONLINEになりました。
[node2] $ sudo systemctl start mysqld
処理4
データは一致していました。
普通に再起動した場合はときに問題無いようですね。
binlogを意図的に欠損させてみる
MySQLのレプリケーション手法の違い | Yakst
こちらのサイトにも書いてあるようにGroup Replicationもbinlogで同期を取っているのでbinlog欠損が発生すると単純に落ちたmysqlを起動してもpositionが分からなくなり復旧できないはずです。
試そうと思いましたが、やってくれている人がいるのでそのまんまご紹介。
やはりそのままでは復旧できないようですね...。dumpを取って復旧が確実そうです。
まとめ
データに差分がある状態での復旧の流れを確認しました。
binlog欠損がある状態での流れはMaster-Slave Replicationと同じでしたね。
binlogを無限に溜める運用は普通はしないと思うので、binlogをexpireするまでにSecondaryのGroup Replicationを再開できれば楽できますね。
次回は、sidecarパターンでMySQL Routerを利用してOpenshiftにdeployしたコンテナからMySQLにアクセスしてみます。
ようやくInnoDB Clusterの要素が揃う..!