MySQL5.7と8.0でのGroup Replicationの設定の違い

この記事は「MySQL Casual Advent Calendar 2018」20日目の記事です。


#はじめに

huatoです。
最近サーバ構築業務から遠ざかってます。
前回検証対応したときに放置していた問題点について再検証してみました。
検証目的での環境構築作業を簡略するために作成したansible playbookについても紹介しています。


前回検証時に放置してた問題点とは

https://qiita.com/huato/items/e090c56393b54e6451af
loose-group_replication_group_seedsのportは当初5.7の頃と同じ6606を設定していたが GRが正常動作しないため、エラーログを元に33061に変更

ずっと腹落ちしなかったので再検証しました。

#結果だけ先に書くと
https://dev.mysql.com/doc/refman/8.0/en/group-replication-configuring-instances.html
このページには記載が見受けられないが必須パラメータが増えていたので追加設定するか
native_passwordでgroup replicationが使用するユーザを作成しても暫定対応可能

```
group_replication_recovery_public_key_path
group_replication_recovery_get_public_key
```

#環境

CentOS Linux release 7.6.1810 (Core)
CPU:4core
RAM:4GB
Disk:40GB
MySQL 5.7.24
      8.0.13

server1: 192.168.102.43 Primary
server2: 192.168.102.44 Secondary
server3: 192.168.102.45 Secondary

#OS周りの設定


検証目的なのでfirewalldを停止します。

```
systemctl stop firewalld
systemctl disable firewalld
```

selinuxも止めます。

```
setenforce 0
sed -i 's/SELINUX=permissive/SELINUX=disabled/g' /etc/selinux/config
reboot
```

今回の検証とは直接関係がありませんが
swappinessの設定はtunedが動いてるとsysctlの値が上書きされるので設定しなおします。

```
mkdir /etc/tuned/virtual-guest
cp /usr/lib/tuned/virtual-guest/tuned.conf /etc/tuned/virtual-guest/
vi /etc/tuned/virtual-guest/tuned.conf
vm.swappiness = 30
=>
vm.swappiness = 10
systemctl restart tuned
```

OS側の準備ができたので次はAnsibleで検証環境を整備します。

#Ansibleによる環境構築
ansibleはepelではなくCentOS標準リポジトリを使いました。

```
yum install ansible
インストールされたバージョン
ansible-2.4.2.0-2.el7.noarch
```


早速MySQLのインストールとGroup Replicationの設定をAnsibleで実施します。
本番環境ではパスワードべた書きせず変数にするなどして
エラー判定処理も追加して使いましょう。


template化したmy.cnfの一部

```
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="{{ my_uuid }}"
loose-group_replication_start_on_boot=off
loose-group_replication_auto_increment_increment=1
loose-group_replication_local_address="{{ ansible_host }}:6606"
loose-group_replication_ip_whitelist="
{%- for host in groups[target_group] -%}
{{ hostvars[host].ansible_eth0.ipv4.address }}
{%- if not loop.last %},{% endif -%}
{%- endfor -%}"
loose-group_replication_group_seeds="
{%- for host in groups[target_group] -%}
{{ hostvars[host].ansible_eth0.ipv4.address }}:6606
{%- if not loop.last %},{% endif -%}
{%- endfor -%}"
loose-group_replication_bootstrap_group=off
```

ansibleのhosts指定箇所

```
[test2]
server1 ansible_host=192.168.102.43 set_hostname=db-master my_serverid=1
server2 ansible_host=192.168.102.44 set_hostname=db-slave my_serverid=2
server3 ansible_host=192.168.102.45 set_hostname=db-slave my_serverid=3
```

Group Replicationを組む箇所

```
---
- name: yum MySQL-python.x86_64 install
  yum:
   name: MySQL-python.x86_64
   state: latest
   disablerepo: mysql80-community
   enablerepo: mysql57-community

- name: copy .my.cnf
  copy:
   src: roles/mysql_install/files/.my.cnf
   dest: /root
   group: root
   mode: 600

#rpl_user
- name: create admin user
  mysql_user:
   state: present
   host: "{{ hostvars[item].ansible_host }}"
   name: rpl_user
   password: dummy2
   priv: '*.*:REPLICATION SLAVE'
  with_items: "{{ groups[target_group] }}"

- name: install group replication 1
  shell: /usr/bin/mysql -uroot  -e "reset master;"

- name: install group replication 2
  shell: /usr/bin/mysql -uroot -e "CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='dummy2' FOR CHANNEL 'group_replication_recovery';"

- name: install group replication 3
  shell: /usr/bin/mysql -uroot -e "INSTALL PLUGIN group_replication SONAME 'group_replication.so';"

- name: start group replication 1
  shell: /usr/bin/mysql -uroot -e "SET GLOBAL group_replication_bootstrap_group=ON;"
  when: set_hostname == "db-master"

- name: install group replication 2
  shell: /usr/bin/mysql -uroot -e "START GROUP_REPLICATION;"
  when: set_hostname == "db-master"

- name: install group replication 3
  shell: /usr/bin/mysql -uroot -e "SET GLOBAL group_replication_bootstrap_group=OFF;"
  when: set_hostname == "db-master"

- name: start group replication slave
  shell: /usr/bin/mysql -uroot -e "START GROUP_REPLICATION;"
  when: set_hostname != "db-master"

- name: delete my.cnf
  file:
      path: /root/.my.cnf
      state: absent
```

インストールするMySQLバージョン指定箇所

```
- name: install mysql-community-server
  yum:
   name: mysql-server
   disable_gpg_check: yes
   disablerepo: mysql80-community
   enablerepo: mysql57-community
   state: present
```
実行するplaybook

```
mysqlインストール処理
ansible-playbook -i hosts --extra-vars "hosts=test2 target_group=test2" setup_mysql.yml -k -u huato --ask-su-pass -vvv
group replicationを組む処理
ansible-playbook -i hosts --extra-vars "hosts=test2 target_group=test2" setup_gr.yml -k -u huato --ask-su-pass -vvv
```

mysqlのインストールや設定作業は手打ちでもそこまで手間ではないのですが
Group Replicationはmy.cnfに記載が必要な設定パラメータやコマンド実行の順番が煩雑なので
自動化またはmysql shll経由で作業するとオペレーションミスを防げると思います。

#構築した環境(MySQL 5.7.24)

```
status:
Server version:         5.7.24-log MySQL Community Server (GPL)

mysql> select * from performance_schema.replication_group_members
    -> ;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | efc3fe17-0218-11e9-adb8-00505689ec08 | server3     |        3306 | ONLINE       |
| group_replication_applier | f176a12b-0218-11e9-b945-005056893bba | server1     |        3306 | ONLINE       |
| group_replication_applier | f19fcf16-0218-11e9-ae0b-005056894ac8 | server2     |        3306 | ONLINE       |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
3 rows in set (0.01 sec)
```

状態確認します

```
select member_host from performance_schema.global_status inner join performance_schema.replication_group_members where variable_name='group_replication_primary_member' AND member_id=variable_value;
+-------------+
| member_host |
+-------------+
| server1      |
+-------------+
1 row in set (0.00 sec)
```


問題が発生せず、Group Replicationが組み上がりました。
次はMySQL5.7をremoveしてMySQL8.0をインストールするために
データや設定ファイルを破棄します。

```
systemctl stop mysqld.service
yum -y remove mysql-* ; rm -rf /data /root/.my,cnf /root/.mysql_secret /etc/my.cnf*
```

mysql80-communityに向けて先ほどのyml書き換えてplaybook再実行します

disablerepo: mysql57-community
enablerepo: mysql80-community


一部手打ちした箇所

```
cd /data/
mysqld --initialize-insecure --user=mysql
mysql -uroot --connect-expired-password -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'escVieLL?';"
```

mysql_userモジュール箇所で止まりました。
https://github.com/ansible/ansible/issues/41116

issuesに従って設定を修正します。

```
mysql -uroot --connect-expired-password -e  "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'escVieLL?';"
```

再現できました。RECOVERINGから先に進みません。

#構築した環境(MySQL 8.0.13)
```
Server version:         8.0.13 MySQL Community Server - GPL


mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | bbe2ae8e-0221-11e9-943b-005056893bba | server1     |        3306 | ONLINE       | PRIMARY     | 8.0.13         |
| group_replication_applier | c8f4823f-0221-11e9-8b74-005056894ac8 | server2     |        3306 | RECOVERING   | SECONDARY   | 8.0.13         |
| group_replication_applier | cbce0973-0221-11e9-b151-00505689ec08 | server3     |        3306 | RECOVERING   | SECONDARY   | 8.0.13         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)
```

早速エラーログを確認します、特に気になるメッセージは見当たりません。


もう一度マニュアルを読み直します
https://dev.mysql.com/doc/refman/8.0/en/group-replication-configuring-instances.html

The recommended port for group_replication_local_address is 33061

推奨値らしいのでport 33061に内部通信のポート設定を変更しGroup Replicationを組み直しましたが
状態に変化はありませんでした。

```
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | d6d63760-0229-11e9-9ad7-005056893bba | server1     |        3306 | ONLINE       | PRIMARY     | 8.0.13         |
| group_replication_applier | d9451d13-0229-11e9-8c73-005056894ac8 | server2     |        3306 | RECOVERING   | SECONDARY   | 8.0.13         |
| group_replication_applier | da365faf-0229-11e9-9f43-00505689ec08 | server3     |        3306 | RECOVERING   | SECONDARY   | 8.0.13         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)
```

MySQL5.7と8.0の差分でコネクション周りで関係ありそうなところ、だとcaching_sha2_password?
ということで
試しにrpl_userの認証プラグインをnative_passwordに変更します

```
use mysql
set sql_log_bin=0;
ALTER USER 'rpl_user'@'192.168.102.43' IDENTIFIED WITH mysql_native_password BY 'dummy2';
ALTER USER 'rpl_user'@'192.168.102.44' IDENTIFIED WITH mysql_native_password BY 'dummy2';
ALTER USER 'rpl_user'@'192.168.102.45' IDENTIFIED WITH mysql_native_password BY 'dummy2';
set sql_log_bin=1;
```

動きました!

```
mysql> select * from performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| CHANNEL_NAME              | MEMBER_ID                            | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
| group_replication_applier | d6d63760-0229-11e9-9ad7-005056893bba | server1     |        3306 | ONLINE       | PRIMARY     | 8.0.13         |
| group_replication_applier | d9451d13-0229-11e9-8c73-005056894ac8 | server2     |        3306 | ONLINE       | SECONDARY   | 8.0.13         |
| group_replication_applier | da365faf-0229-11e9-9f43-00505689ec08 | server3     |        3306 | ONLINE       | SECONDARY   | 8.0.13         |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+
3 rows in set (0.00 sec)
```

マニュアルをよく読むと注意の記載がありました
https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html

group_replication_recovery_public_key_path and 
group_replication_recovery_get_public_key system variables serve the same purpose.


#まとめ
MySQL5.7と8.0でGroup Replicationの設定に細かい違いがありました。
この記事が同じ問題で困っている人の助けになれば幸いです。