实验目标回顾
通过本章实验,我们将系统掌握以下内容:
- MySQL 8.3.0 源码编译与部署
- 主从复制架构搭建(异步、GTID、半同步、延迟复制、多线程回放)
- MHA 高可用集群部署与手动/自动切换
- MySQL Group Replication(MGR)多主模式部署
- MySQL Router 读写分离配置
- 使用 Ansible 批量重置 MySQL 环境
核心知识点梳理
| 模块 | 关键知识点 |
|---|---|
| 源码编译 | cmake3 参数、boost 依赖、数据目录初始化 |
| 主从复制 | binlog、relay log、IO/SQL 线程、CHANGE MASTER TO |
| GTID | MASTER_AUTO_POSITION=1、故障切换便利性 |
| 半同步复制 | rpl_semi_sync_master/slave 插件、ACK 超时降级 |
| 延迟复制 | SOURCE_DELAY=N、误操作快速恢复 |
| 多线程回放 | slave_parallel_workers、LOGICAL_CLOCK |
| MHA | Manager/Node 架构、VIP 漂移、死主切换与活主切换 |
| MGR | 组复制多主模式、Paxos 一致性、节点 ONLINE 状态 |
| Router | 读写分离端口、round-robin/first-available 策略 |
| Ansible | inventory、playbook、批量初始化 MySQL |
实验过程中遇到的问题及解决方法
(文章末尾)
一、Mysql的源码编译
下载安装包
bash
[root@mysql-node1 ~]# wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-8.3.0.tar.gz
源码编译
bash
[root@mysql-node1 ~]# dnf install cmake3 gcc git bison openssl-devel ncurses-devel systemd-devel rpcgen.x86_64 libtirpc-devel-1.3.3-9.el9.x86_64.rpm gcc-toolset-12-gcc gcc-toolset-12-gcc-c++ gcc-toolset-12-binutils gcc-toolset-12-annobin-annocheck gcc-toolset-12-annobin-plugin-gcc -y
[root@mysql-node1 ~]# tar zxf mysql-boost-8.3.0.tar.gz
[root@mysql-node1 ~]# cd mysql-8.3.0/
[root@mysql-node1 mysql-8.3.0]# mkdir build
[root@mysql-node1 mysql-8.3.0]# cd build/
[root@mysql-node1 build]# cmake3 .. -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_DATADIR=/data/mysql -DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_EXTRA_CHARSETS=all -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_unicode_ci -DWITH_BOOST=bundled -DWITH_SSL=system -DWITH_DEBUG=OFF
[root@mysql-node1 build]# make
部署mysql
bash
[root@mysql-node1 build]# make install
[root@mysql-node1 build]# cd /usr/local/mysql/
[root@mysql-node1 mysql]# vim ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
export PATH=$PATH:/usr/local/mysql/bin #设置mysql运行环境的环境变量
[root@mysql-node1 mysql]# source ~/.bash_profile
[root@mysql-node1 mysql]# useradd -r -s /sbin/nologin -M mysql
[root@mysql-node1 mysql]# mkdir -p /data/mysql
[root@mysql-node1 mysql]# chown mysql.mysql /data/mysql
#或者
[root@mysql-node1 mysql]# chown mysql:mysql /data/mysql
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=10
mysql数据结构初始化
bash
[root@mysql-node1 build]# mysqld --initialize --user=mysql
2026-02-26T02:33:31.103872Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2026-02-26T02:33:31.105547Z 0 [System] [MY-013169] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.3.0) initializing of server in progress as process 40379
2026-02-26T02:33:31.116172Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2026-02-26T02:33:31.472616Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2026-02-26T02:33:32.329569Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: *cpw*U8whdXh
2026-02-26T02:33:34.042537Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.

启动mysql
bash
[root@mysql-node1 support-files]# dnf install initscripts-10.11.8-4.el9.x86_64 -y
[root@mysql-node1 support-files]# cd /usr/local/mysql/support-files/
[root@mysql-node1 support-files]# cp -p mysql.server /etc/init.d/mysqld
[root@mysql-node1 support-files]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node1.err'.
. SUCCESS!
#开机启动
[root@mysql-node1 support-files]# chkconfig --level 35 mysqld on
[root@mysql-node1 ~]# chkconfig --level 35 --list
注:该输出结果只显示 SysV 服务,并不包含
原生 systemd 服务。SysV 配置数据
可能被原生 systemd 配置覆盖。
要列出 systemd 服务,请执行 'systemctl list-unit-files'。
查看在具体 target 启用的服务请执行
'systemctl list-dependencies [target]'。
mysqld 0:关 1:关 2:开 3:开 4:开 5:开 6:关
mysql的安全初始化
bash
[root@mysql-node1 ~]# mysql_secure_installation
Securing the MySQL server deployment.
Enter password for user root:
The existing password for the user account root has expired. Please set a new password.
New password:
Re-enter new password:
VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?
Press y|Y for Yes, any other key for No: no
Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : no
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.
Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
- Dropping test database...
Success.
- Removing privileges on test database...
Success.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.
All done!
mysql-node2完整配置
mysql-node3配置和2完全一致
开始前,在node1中执行
bash
[root@mysql-node1 ~]# scp -rp /usr/local/mysql/ root@172.25.254.20:/usr/local/
bash
[root@mysql-node2 ~]# useradd -r -s /sbin/nologin mysql
[root@mysql-node2 ~]# mkdir -p /data/mysql
[root@mysql-node2 ~]# chown mysql:mysql /data/mysql
[root@mysql-node2 ~]# vim ~/.bash_profile
#添加下面的内容
export PATH=$PATH:/usr/local/mysql/bin
[root@mysql-node2 ~]# source ~/.bash_profile
[root@mysql-node2 ~]# dnf whatprovides /etc/init.d
正在更新 Subscription Management 软件仓库。
无法读取客户身份
本系统尚未在权利服务器中注册。可使用 "rhc" 或 "subscription-manager" 进行注册。
上次元数据过期检查:42 days, 22:48:44 前,执行于 2026年01月14日 星期三 11时52分50秒。
chkconfig-1.24-2.el9.x86_64 : A system tool for maintaining the /etc/rc*.d hierarchy
仓库 :BaseOS
匹配来源:
文件名 :/etc/init.d
initscripts-10.11.8-4.el9.x86_64 : Basic support for legacy System V init scripts
仓库 :BaseOS
匹配来源:
文件名 :/etc/init.d
[root@mysql-node2 ~]# dnf install initscripts-10.11.8-4.el9.x86_64 -y
正在更新 Subscription Management 软件仓库。
无法读取客户身份
本系统尚未在权利服务器中注册。可使用 "rhc" 或 "subscription-manager" 进行注册。
AppStream 3.1 MB/s | 3.2 kB 00:00
BaseOS 2.7 MB/s | 2.7 kB 00:00
依赖关系解决。
=====================================================================================
软件包 架构 版本 仓库 大小
=====================================================================================
安装:
initscripts x86_64 10.11.8-4.el9 BaseOS 232 k
安装依赖关系:
chkconfig x86_64 1.24-2.el9 BaseOS 182 k
事务概要
=====================================================================================
安装 2 软件包
总计:414 k
安装大小:1.8 M
下载软件包:
运行事务检查
事务检查成功。
运行事务测试
事务测试成功。
运行事务
准备中 : 1/1
安装 : chkconfig-1.24-2.el9.x86_64 1/2
安装 : initscripts-10.11.8-4.el9.x86_64 2/2
运行脚本: initscripts-10.11.8-4.el9.x86_64 2/2
Created symlink /etc/systemd/system/sysinit.target.wants/import-state.service → /usr/ lib/systemd/system/import-state.service.
Created symlink /etc/systemd/system/sysinit.target.wants/loadmodules.service → /usr/l ib/systemd/system/loadmodules.service.
验证 : chkconfig-1.24-2.el9.x86_64 1/2
验证 : initscripts-10.11.8-4.el9.x86_64 2/2
已更新安装的产品。
已安装:
chkconfig-1.24-2.el9.x86_64 initscripts-10.11.8-4.el9.x86_64
完毕!
[root@mysql-node2 ~]# cp -p /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
[root@mysql-node2 ~]# mysqld --initialize --user=mysql
2026-02-26T02:45:08.428229Z 0 [System] [MY-015017] [Server] MySQL Server Initialization - start.
2026-02-26T02:45:08.430297Z 0 [System] [MY-013169] [Server] /usr/local/mysql/bin/mysqld (mysqld 8.3.0) initializing of server in progress as process 30340
2026-02-26T02:45:08.455321Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2026-02-26T02:45:09.587016Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2026-02-26T02:45:10.880631Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: dYrYIS,!S2G,
2026-02-26T02:45:13.183911Z 0 [System] [MY-015018] [Server] MySQL Server Initialization - end.
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=20
[root@mysql-node2 ~]# chkconfig mysqld on
[root@mysql-node2 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node2.err'.
. SUCCESS!
[root@mysql-node2 ~]# mysql_secure_installation
Securing the MySQL server deployment.
Enter password for user root:
The existing password for the user account root has expired. Please set a new password.
New password:
Re-enter new password:
VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?
Press y|Y for Yes, any other key for No: no
Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : no
... skipping.
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.
Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.
By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
- Dropping test database...
Success.
- Removing privileges on test database...
Success.
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.
All done!
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.3.0 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> \q
Bye
测试

二、Mysql集群实战--主从复制
编写my.cnf 主配置文件
bash
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=10
log-bin=mysql-bin
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=20
log-bin=mysql-bin
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=30
log-bin=mysql-bin
#在三台主机中重启数据库
[root@mysql-node1 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS!
Starting MySQL. SUCCESS!
[root@mysql-node2 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS!
Starting MySQL. SUCCESS!
[root@mysql-node3 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS!
Starting MySQL. SUCCESS!
建立同步时需要用到的数据库账号
bash
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.3.0 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show variables like 'default_authentication_plugin';
+-------------------------------+-----------------------+
| Variable_name | Value |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+
1 row in set (0.00 sec)
mysql> create user yu@'%' identified with mysql_native_password by 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> select user from mysql.user;
+------------------+
| user |
+------------------+
| yu |
| mysql.infoschema |
| mysql.session |
| mysql.sys |
| root |
+------------------+
5 rows in set (0.00 sec)
mysql> grant replication slave on *.* to yu@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> show grants for yu@'%';
+--------------------------------------------+
| Grants for yu@% |
+--------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `yu`@`%` |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> \q
Bye
配置数据库一主一从
开始前需要在master主机中查看一下,找出bin文件和position
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 657 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set, 1 warning (0.00 sec)
mysql
#在slave主机中
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.3.0 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> change master to MASTER_HOST='172.25.254.10',MASTER_USER='yu',MASTER_PASSWORD='yu',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=657;
Query OK, 0 rows affected, 8 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 657
Relay_Log_File: mysql-node2-relay-bin.000002
Relay_Log_Pos: 328
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes #数据同步成功
Slave_SQL_Running: Yes #通过同步过来的数据做日志回访成功
测试
mysql
[root@mysql-node1 ~]# mysql -uroot -lee #在master中建立库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.01 sec)
mysql> create database liouo;
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| liouo |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
在slave主机中可以查看到数据
mysql
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| liouo |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)

向当前一主一从中加入新的数据库
mysql
#模拟一主一从中已经存在数据情况
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.3.0 Source distribution
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create table liouo.userlist (
-> name varchar(10) not null,
-> pass varchar(50) not null
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> use liouo;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> desc liouo.userlist;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(10) | NO | | NULL | |
| pass | varchar(50) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.01 sec)
mysql> insert into liouo.userlist values ('user1','123');
Query OK, 1 row affected (0.00 sec)
mysql> select * from liouo.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
+-------+------+
1 row in set (0.00 sec)
# 加入新从库时需要手动拉平数据
[root@mysql-node1 ~]# mysqldump -uroot -pyu liouo > liouo.sql
[root@mysql-node1 ~]# scp liouo.sql root@172.25.254.30:/root/
liouo.sql 100% 1939 946.4KB/s 00:00
# 在新加入的mysql-node3中
[root@mysql-node3 ~]# mysql -uroot -pyu -e "create database liouo;"
[root@mysql-node3 ~]# mysql -uroot -pyu liouo < liouo.sql
[root@mysql-node3 ~]# mysql -uroot -pyu
mysql> select * from liouo.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
+-------+------+
1 row in set (0.00 sec)
将新库加入主从结构中
mysql
#在master中查看日志的id
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 1382 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set, 1 warning (0.00 sec)
[root@mysql-node3 ~]# mysql -uroot -pyu
mysql> change master to MASTER_HOST='172.25.254.10',MASTER_USER='yu',MASTER_PASSWORD='yu',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1382;
Query OK, 0 rows affected, 8 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 1382
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 328
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
测试一主两从
bash
#在master中建立数据
[root@mysql-node1 ~]# mysqldump -uroot -pyu
mysql> insert into liouo.userlist values ('user2','123');
Query OK, 1 row affected (0.00 sec)
mysql> select * from liouo.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
| user2 | 123 |
+-------+------+
2 rows in set (0.00 sec)
在新加入的slave中查看信息

三、mysql主从架构中的使用技巧及优化
延迟复制
mysql
#在指定需要延迟同步的slave主机中,如果主机中安装数据库的版本是8以上
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> show slave status \G
*************************** 1. row ***************************
SQL_Delay: 0
mysql> stop replica;
Query OK, 0 rows affected (0.02 sec)
mysql> change replication source to SOURCE_DELAY=60;
Query OK, 0 rows affected (0.03 sec)
mysql> start replica;
Query OK, 0 rows affected (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
SQL_Delay: 60
# 或者直接执行
[root@mysql-node2 ~]# mysql -uroot -plee -e "show slave status\G;" | grep SQL_Delay
mysql: [Warning] Using a password on the command line interface can be insecure.
SQL_Delay: 60
在master主机中对数据进行更改
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> delete from liouo.userlist where name='user1';
Query OK, 1 row affected (0.04 sec)
mysql> select * from liouo.userlist;
+-------+------+
| name | pass |
+-------+------+
| user2 | 123 |
+-------+------+
1 row in set (0.00 sec)
在未被延迟的slave数据库中查看是否数据操作动作被同步
mysql
[root@mysql-node3 ~]# mysql -uroot -pyu
mysql> show slave status \G
*************************** 1. row ***************************
SQL_Delay: 0
mysql> select * from liouo.userlist;
+-------+------+
| name | pass |
+-------+------+
| user2 | 123 |
+-------+------+
1 row in set (0.00 sec)
直接在被设定延迟复制的主机mysql-node2上测试,看是否同步;等待延迟时间过后再次查看,信息是否同步

慢查询日志
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
# 查看慢查询日志是否开启
mysql> show variables like "slow%";
+---------------------+----------------------------------+
| Variable_name | Value |
+---------------------+----------------------------------+
| slow_launch_time | 2 |
| slow_query_log | OFF |
| slow_query_log_file | /data/mysql/mysql-node1-slow.log |
+---------------------+----------------------------------+
3 rows in set (0.02 sec)
# 开启慢查询日志
mysql> set global slow_query_log=ON;
Query OK, 0 rows affected (0.01 sec)
# 检测是否成功开启慢查询日志
mysql> show variables like "slow%";
+---------------------+----------------------------------+
| Variable_name | Value |
+---------------------+----------------------------------+
| slow_launch_time | 2 |
| slow_query_log | ON |
| slow_query_log_file | /data/mysql/mysql-node1-slow.log |
+---------------------+----------------------------------+
3 rows in set (0.00 sec)
# 查看慢查询的阈值
mysql> show variables like "long%";
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
# 修改慢查询的阈值,注意此处不用加global
mysql> set long_query_time=4;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "long%";
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 4.000000 |
+-----------------+----------+
1 row in set (0.00 sec)
测试
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> select sleep (4);
+-----------+
| sleep (4) |
+-----------+
| 0 |
+-----------+
1 row in set (4.01 sec)
mysql> select sleep (2); #不会生成慢查询日志
+-----------+
| sleep (2) |
+-----------+
| 0 |
+-----------+
1 row in set (2.01 sec)

gtid模式
mysql
#在master和slave中默认gtid模式是未开启的
[root@mysql-node1 ~]# mysql -uroot -pyu
在所有主机中加入参数
bash
[root@mysql-node1 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=10
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node1 ~]# /etc/init.d/mysqld restart
Shutting down MySQL........... SUCCESS!
Starting MySQL. SUCCESS!
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=20
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node2 ~]# /etc/init.d/mysqld restart
Shutting down MySQL........... SUCCESS!
Starting MySQL. SUCCESS!
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=30
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node3 ~]# /etc/init.d/mysqld restart
Shutting down MySQL........... SUCCESS!
Starting MySQL. SUCCESS!
mysql
#在三台主机中分别查看gtid模式是否开启
mysql> show variables like "%gtid%";
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
9 rows in set (0.01 sec)
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000004 | 158 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set, 1 warning (0.01 sec)
mysql
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> show variables like "%gtid%";
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
9 rows in set (0.04 sec)
#在从库中停止slave功能;
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to MASTER_HOST='172.25.254.10',MASTER_USER='yu',MASTER_PASSWORD='yu',MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 7 warnings (0.04 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-node2-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: No
Slave_SQL_Running: No
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-node2-relay-bin.000002
Relay_Log_Pos: 375
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
mysql
[root@mysql-node3 ~]# mysql -uroot -pyu
mysql> show variables like "%gtid%";
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | ON |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
9 rows in set (0.03 sec)
#在从库中停止slave功能;
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> change master to MASTER_HOST='172.25.254.10',MASTER_USER='yu',MASTER_PASSWORD='yu',MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 7 warnings (0.05 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State:
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File:
Read_Master_Log_Pos: 4
Relay_Log_File: mysql-node3-relay-bin.000001
Relay_Log_Pos: 4
Relay_Master_Log_File:
Slave_IO_Running: No
Slave_SQL_Running: No
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.02 sec)
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: yu
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 375
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

多线程回放
mysql
#在slave主机中默认回方日志时使用单线程回放
mysql> show processlist;

bash
#开启多线程回放日志(在slave主中)
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
server-id=20
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
relay_log_recovery=ON
[root@mysql-node2 ~]# /etc/init.d/mysqld restart
Shutting down MySQL. SUCCESS!
Starting MySQL. SUCCESS!
#查看更改生效信息
mysql> show processlist;

半同步模式
mysql
#在master主机中操作
[root@mysql-node1 ~]# vim /etc/my.cnf
rpl_semi_sync_master_enabled=1
mysql> install plugin rpl_semi_sync_master SONAME 'semisync_master.so';
mysql> set global rpl_semi_sync_master_enabled = 1;
mysql
#在slave主机中
[root@mysql-node2~3 ~]# vim /etc/my.cnf
rpl_semi_sync_slave_enabled=1
mysql> install plugin rpl_semi_sync_slave SONAME 'semisync_slave.so';
mysql> set global rpl_semi_sync_slave_enabled = 1;
mysql> stop slave IO_THREAD;
mysql> start slave IO_THREAD
mysql> select plugin_name,plugin_status from information_schema.plugins where plugin_name like '%semi%';
+---------------------+---------------+
| plugin_name | plugin_status |
+---------------------+---------------+
| rpl_semi_sync_slave | ACTIVE |
+---------------------+---------------+
1 row in set (0.00 sec)
mysql> show variables like 'rpl_semi_sync%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.00 sec)
mysql> show status like 'rpl_semi_sync%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)
mysql
#测试:
#在主库中
mysql> insert into liouo.userlist values ('user7','123');
Query OK, 1 row affected (0.02 sec)
mysql> SHOW VARIABLES LIKE 'rpl_semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
mysql> show status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 1 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 2013 |
| Rpl_semi_sync_master_tx_wait_time | 2013 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
#模拟ack故障 在所有slave主机中
mysql> stop slave IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.00 sec)
#在主库写入数据
mysql> insert into liouo.userlist values ('user8','123');
Query OK, 1 row affected (10.01 sec)
mysql> show status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 2 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 1 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 3598 |
| Rpl_semi_sync_master_tx_wait_time | 7197 |
| Rpl_semi_sync_master_tx_waits | 2 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 2 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
#恢复故障 在所有slave主机中
mysql> start SLAVE IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> insert into liouo.userlist values ('user6','123');
Query OK, 1 row affected (0.04 sec)
mysql> show status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 1 |
| Rpl_semi_sync_master_no_times | 0 |
| Rpl_semi_sync_master_no_tx | 0 |
| Rpl_semi_sync_master_status | ON |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 2013 |
| Rpl_semi_sync_master_tx_wait_time | 2013 |
| Rpl_semi_sync_master_tx_waits | 1 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 1 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
mysql> insert into liouo.userlist values ('user7','123');
Query OK, 1 row affected (0.02 sec)
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> stop slave IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.01 sec)
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> insert into liouo.userlist values ('user8','123');
Query OK, 1 row affected (10.01 sec)
mysql> show status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 2 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 1 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 3598 |
| Rpl_semi_sync_master_tx_wait_time | 7197 |
| Rpl_semi_sync_master_tx_waits | 2 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 2 |
+--------------------------------------------+-------+
14 rows in set (0.01 sec)
四、Mysql-MHA高可用集群
配置Mha-manager
bash
[root@mha ~]# unzip MHA-7.zip
[root@mha ~]# cd MHA-7/
[root@mha MHA-7]# dnf install perl perl-DBD-MySQL perl-CPAN -y
[root@mha MHA-7]# cpan
Loading internal logger. Log::Log4perl recommended for better logging
CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.
Would you like to configure as much as possible automatically? [yes] yes
cpan[1]> install Config::Tiny
cpan[2]> install Log::Dispatch
cpan[3]> install Mail::Sender
Specify defaults for Mail::Sender? (y/N) y
Default encoding of message bodies (N)one, (Q)uoted-printable, (B)ase64: n
cpan[4]> install Parallel::ForkManager
cpan[5]>exit
[root@mha MHA-7]# rpm -ivh mha4mysql-manager-0.58-0.el7.centos.noarch.rpm mha4mysql-node-0.58-0.el7.centos.noarch.rpm --nodeps
在slave中安装相应软件
bash
[root@mha MHA-7]# for i in 10 20 30
> do
> scp mha4mysql-node-0.58-0.el7.centos.noarch.rpm root@172.25.254.$i:/mnt
> ssh -l root 172.25.254.$i "rpm -ivh /mnt/mha4mysql-node-0.58-0.el7.centos.noarch.rpm --nodeps"
> done
Warning: Permanently added '172.25.254.10' (ED25519) to the list of known hosts.
mha4mysql-node-0.58-0.el7.centos.noarch.rpm 100% 35KB 16.9MB/s 00:00
Verifying... ########################################
准备中... ########################################
正在升级/安装...
mha4mysql-node-0.58-0.el7.centos ########################################
Warning: Permanently added '172.25.254.20' (ED25519) to the list of known hosts.
mha4mysql-node-0.58-0.el7.centos.noarch.rpm 100% 35KB 28.2MB/s 00:00
Verifying... ########################################
准备中... ########################################
正在升级/安装...
mha4mysql-node-0.58-0.el7.centos ########################################
Warning: Permanently added '172.25.254.30' (ED25519) to the list of known hosts.
mha4mysql-node-0.58-0.el7.centos.noarch.rpm 100% 35KB 20.1MB/s 00:00
Verifying... ########################################
准备中... ########################################
正在升级/安装...
mha4mysql-node-0.58-0.el7.centos ########################################
修改MHA-Manager中的检测代码
bash
[root@mha MHA-7]# vim /usr/share/perl5/vendor_perl/MHA/NodeUtil.pm
199 #sub parse_mysql_major_version($) {
200 # my $str = shift;
201 # my $result = sprintf( '%03d%03d', $str =~ m/(\d+)/g );
202 # return $result;
203 #}
sub parse_mysql_major_version($) {
my $str = shift;
my @nums = $str =~ m/(\d+)/g;
my $result = sprintf( '%03d%03d', $nums[0]//0, $nums[1]//0);
return $result;
}
为MHA建立远程登录用户
bash
#在master主机中
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> create user root@'%' identified with mysql_native_password by 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> grant all on *.* tO root@'%' ;
Query OK, 0 rows affected (0.00 sec)
生成MHA-manager的配置文件模板
bash
[root@mha MHA-7]# tar zxf mha4mysql-manager-0.58.tar.gz
[root@mha MHA-7]# cd mha4mysql-manager-0.58
[root@mha mha4mysql-manager-0.58]# mkdir /etc/masterha/ -p
[root@mha mha4mysql-manager-0.58]# cat samples/conf/masterha_default.cnf samples/conf/app1.cnf > /etc/masterha/app1.cnf
修改配置文件
bash
[root@mha mha4mysql-manager-0.58]# vim /etc/masterha/app1.cnf
[server default]
user=root
password=yu
ssh_user=root
repl_user=root
repl_password=yu
master_binlog_dir= /data/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.2
ping_interval=3
# master_ip_failover_script= /script/masterha/master_ip_failover
# shutdown_script= /script/masterha/power_manager
# report_script= /script/masterha/send_report
# master_ip_online_change_script= /script/masterha/master_ip_online_change
[server default]
manager_workdir=/etc/masterha
manager_log=/etc/masterha/app1/mha.log
[server1]
hostname=172.25.254.10
candidate_master=1
check_repl_delay=0
[server2]
hostname=172.25.254.20
candidate_master=1
check_repl_delay=0
[server3]
hostname=172.25.254.30
no_master=1
检测环境
bash
[root@mha mha4mysql-manager-0.58]# masterha_check_ssh --conf=/etc/masterha/app1.cnf
[root@mha mha4mysql-manager-0.58]# masterha_check_repl --conf=/etc/masterha/app1.cnf


在slave中安装mha-node软件依赖
bash
#在所有的数据库主机中安装依赖
[root@mysql-node1~3 ~]# dnf install perl perl-DBD-MySQL perl-CPAN -y
[root@mysql-node1~3 ~]# tar zxf cpan_plugin.tar.gz
[root@mysql-node1~3 ~]# cpan
Loading internal logger. Log::Log4perl recommended for better logging
CPAN.pm requires configuration, but most of it can be done automatically.
If you answer 'no' below, you will enter an interactive dialog for each
configuration option instead.
Would you like to configure as much as possible automatically? [yes] yes
cpan[1]> install Config::Tiny
cpan[2]> install Log::Dispatch
cpan[3]> install Mail::Sender
Specify defaults for Mail::Sender? (y/N) y
Default encoding of message bodies (N)one, (Q)uoted-printable, (B)ase64: n
cpan[4]> install Parallel::ForkManager
cpan[5]>exit
#验证组建是否安装成功
[root@mysql-node1~3 ~]# perl -MConfig::Tiny -e 'print "OK\n"'
OK
[root@mysql-node1~3 ~]# perl -MLog::Dispatch -e 'print "OK\n"'
OK
[root@mysql-node1~3 ~]# perl -MMail::Sender -e 'print "OK\n"'
Mail::Sender is deprecated and you should look to Email::Sender instead at -e line 0.
OK
[root@mysql-node1~3 ~]# perl -MParallel::ForkManager -e 'print "OK\n"'
OK
五、集群切换操作
手动切换
master无故障切换
默认状态下:10是主库,20和30是从库;即在10上输入下面命令时,返回空;在20和30上查看时,显示如下


bash
#执行切换,把master切换到20
[root@mha ~]# masterha_master_switch \
> --conf=/etc/masterha/app1.cnf \
> --master_state=alive \
> --new_master_host=172.25.254.20 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \
> --running_updates_limit=10000
# 或者是
[root@mha ~]# masterha_master_switch --conf=/etc/masterha/app1.cnf --master_state=alive --new_master_host=172.25.254.20 --new_master_port=3306 --orig_master_is_new_slave --running_updates_limit=10000
[root@mha ~]# masterha_master_switch \
> --conf=/etc/masterha/app1.cnf \
> --master_state=alive \
> --new_master_host=172.25.254.20 \
> --new_master_port=3306 \
> --orig_master_is_new_slave \
> --running_updates_limit=10000
It is better to execute FLUSH NO_WRITE_TO_BINLOG TABLES on the master before switching. Is it ok to execute on 172.25.254.10 (172.25.254.10:3306)? (YES/no): yes # 输入
Starting master switch from 172.25.254.10(172.25.254.10:3306) to 172.25.254.20(172.25.254.20:3306)? (yes/NO): yes # 输入
Sat Mar 7 11:31:32 2026 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER T O MASTER_HOST='172.25.254.20', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='root', MASTER_PASSWORD='xxx';
172.25.254.20(172.25.254.20:3306) completed successfully.
看到successfully即为成功

效果:
查看集群状态


master故障后切换
(1)检查环境
bash
# 在执行前可以在mha节点执行下面语句,为验证当前集群健康
masterha_check_repl --conf=/etc/masterha/app1.cnf
# 输出MySQL Replication Health is OK.即为健康
(2)模拟当前主库172.25.254.20宕机
bash
[root@mysql-node2 ~]# /etc/init.d/mysqld stop
Shutting down MySQL......... SUCCESS!
(3)执行手动故障切换
bash
[root@mha ~]# masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=172.25.254.20 --dead_master_port=3306 --new_master_host=172.25.254.10 --new_master_port=3306 --ignore_last_failover
--dead_master_ip=<dead_master_ip> is not set. Using 172.25.254.20.
Master 172.25.254.20(172.25.254.20:3306) is down!
Started manual(interactive) failover.
Selected 172.25.254.10(172.25.254.10:3306) as a new master.
172.25.254.10(172.25.254.10:3306): OK: Applying all logs succeeded.
172.25.254.30(172.25.254.30:3306): ERROR: Failed on waiting gtid exec set on master.
Master failover to 172.25.254.10(172.25.254.10:3306) done, but recovery on slave partially failed.
(4)删除锁文件
bash
[root@mha ~]# ls /etc/masterha/
app1.cnf app1.failover.complete---->#(锁文件)
[root@mha ~]# rm -rf /etc/masterha/app1.failover.complete
[root@mha ~]# ls /etc/masterha/
app1.cnf
mysql
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> stop slave;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> reset slave all;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show slave status \G;
Empty set, 1 warning (0.00 sec)
在20上
mysql
[root@mysql-node2 ~]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> reset slave all;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='root', MASTER_PASSWORD='yu', MASTER_AUTO_POSITION=1;
Query OK, 0 rows affected, 7 warnings (0.02 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> \q
Bye
[root@mysql-node2 ~]# mysql -uroot -pyu -e "show slave status\G;" | head -n 15
mysql: [Warning] Using a password on the command line interface can be insecure.
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: root
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000008
Read_Master_Log_Pos: 422
Relay_Log_File: mysql-node2-relay-bin.000002
Relay_Log_Pos: 422
Relay_Master_Log_File: mysql-bin.000008
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
最后查看三个节点的状态
1.node1返回空值,172.25.254.10为主库

2.node2和node3返回值一致,均为从库


自动切换
方便观察建议开启两个shell
bash
[root@mha ~]# > /etc/masterha/*.log
[root@mha ~]# watch -n 1 cat /etc/masterha/mha.log
检查配置文件书写路径是否正确
bash
[root@mha ~]# vim /etc/masterha/app1.cnf
[server default]
user=root
password=yu
ssh_user=root
repl_user=root
repl_password=yu
master_binlog_dir= /data/mysql
remote_workdir=/tmp
secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.2
ping_interval=3
[server default]
manager_workdir=/etc/masterha # 日志文件存储路径
manager_log=/etc/masterha/mha.log # 日志文件
[server1]
hostname=172.25.254.10
candidate_master=1
check_repl_delay=0
[server2]
hostname=172.25.254.20
candidate_master=1
check_repl_delay=0
[server3]
hostname=172.25.254.30
no_master=1
开启自动切换功能
bash
[root@mha ~]# masterha_manager --conf=/etc/masterha/app1.cnf &
[root@mha ~]# jobs
[1]+ 运行中 masterha_manager --conf=/etc/masterha/app1.cnf &

模拟故障
bash
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
vip功能及vip的启动切换
bash
[root@mha ~]# ll MHA-7/master_ip_*
-rw-r--r-- 1 root root 2156 1月 14 2021 MHA-7/master_ip_failover
-rw-r--r-- 1 root root 3813 1月 14 2021 MHA-7/master_ip_online_change
[root@mha ~]# mkdir /etc/masterha/scripts
[root@mha ~]# cp MHA-7/master_ip_* /etc/masterha/scripts
[root@mha ~]# vim /etc/masterha/app1.cnf
master_ip_failover_script= /etc/masterha/scripts/master_ip_failover
master_ip_online_change_script= /etc/masterha/scripts/master_ip_online_change
[root@mha ~]# vim /etc/masterha/scripts/master_ip_failover
my $vip = '172.25.254.100/24';
[root@mha ~]# vim /etc/masterha/scripts/master_ip_online_change
my $vip = '172.25.254.100/24';
# 注释掉下面这行
[root@mha ~]# vim /etc/masterha/app1.cnf
# secondary_check_script= masterha_secondary_check -s 172.25.254.10 -s 172.25.254.2
[root@mysql-node1 ~]# ip a a 172.25.254.100/24 dev eth0

测试
bash
[root@mha ~]# masterha_manager --conf=/etc/masterha/app1.cnf &
[root@mha ~]# jobs
[1]+ 运行中 masterha_manager --conf=/etc/masterha/app1.cnf &

模拟故障,关闭mysql master
bash
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
Shutting down MySQL........... SUCCESS!
观察监控中的状态,此时vip漂移到20上


六、还原mysql所有节点
利用ansible还原所有节点
bash
#利用ansible还原所有节点
[root@mha ~]# vim /etc/yum.repos.d/epel.repo
[epel]
name = epel
baseurl = https://mirrors.aliyun.com/epel-archive/9.6/Everything/x86_64/
gpgcheck = 0
[root@mha yum.repos.d]# dnf install ansible -y
[root@mha yum.repos.d]# ansible --version
ansible [core 2.14.18]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.9/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.9.21 (main, Feb 10 2025, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
[root@mha ~]# useradd devops
[root@mha ~]# echo yu | passwd --stdin devops
更改用户 devops 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[devops@mha ansible]$ vim ansible.cfg
[defaults]
inventory=./inventory
remote_user=root
host_key_checking=false
[privilege_escalation]
become=False
[devops@mha ansible]$ vim inventory
[mysql]
172.25.254.10
172.25.254.20
172.25.254.30
[devops@mha ansible]$ ansible mysql -m ping
172.25.254.30 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
172.25.254.20 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
172.25.254.10 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
[devops@mha ansible]$ ansible mysql -m shell -a "whoami"
172.25.254.30 | CHANGED | rc=0 >>
root
172.25.254.20 | CHANGED | rc=0 >>
root
172.25.254.10 | CHANGED | rc=0 >>
root
[devops@mha ansible]$ ansible mysql -m user -a 'name=devops'
[devops@mha ansible]$ ansible mysql -m shell -a 'echo devops | passwd --stdin devops'
[devops@mha ansible]$ ansible mysql -m shell -a 'echo "devops ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers'
[devops@mha ansible]$ ansible all -m file -a 'path=/home/devops/.ssh owner=devops group=devops mode="0700" state=directory'
[devops@mha ansible]$ ansible all -m copy -a 'src=/home/devops/.ssh/authorized_keys dest=/home/devops/.ssh/authorized_keys owner=devops group=devops mode='0600''
[devops@mha ansible]$ cat >ansible.cfg <<EOF
[defaults]
inventory=./inventory
remote_user=devops
host_key_checking=false
[privilege_escalation]
become=True
become_ask_pass=False
become_method=sudo
become_user=root
EOF
[devops@mha ansible]$ ansible all -m shell -a 'whoami'
172.25.254.20 | CHANGED | rc=0 >>
root
172.25.254.30 | CHANGED | rc=0 >>
root
172.25.254.10 | CHANGED | rc=0 >>
root
[devops@mha ansible]$ vim clear_mysql.yml
- name: reset mysql
hosts: mysql
tasks:
- name: stop mysql
shell: '/etc/init.d/mysqld stop'
ignore_errors: yes
- name: delete mysql data
file:
path: /data/mysql
state: absent
- name: crate data directroy
file:
path: /data/mysql
state: directory
owner: mysql
group: mysql
- name: initialize mysql
shell: '/usr/local/mysql/bin/mysqld --initialize --user=mysql'
[devops@mha ansible]$ ansible-playbook clear_mysql.yml -vv | grep password
续6.1(未修改的)
bash
[devops@mha ansible]$
[devops@mha ansible]$ ansible mysql -m user -a 'name=devops'
172.25.254.20 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/devops",
"name": "devops",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1000
}
172.25.254.30 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/devops",
"name": "devops",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1000
}
172.25.254.10 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"comment": "",
"create_home": true,
"group": 1000,
"home": "/home/devops",
"name": "devops",
"shell": "/bin/bash",
"state": "present",
"system": false,
"uid": 1000
}
[devops@mha ansible]$ ansible mysql -m shell -a 'id devops'
172.25.254.20 | CHANGED | rc=0 >>
用户id=1000(devops) 组id=1000(devops) 组=1000(devops)
172.25.254.30 | CHANGED | rc=0 >>
用户id=1000(devops) 组id=1000(devops) 组=1000(devops)
172.25.254.10 | CHANGED | rc=0 >>
用户id=1000(devops) 组id=1000(devops) 组=1000(devops)
[devops@mha ansible]$ ansible mysql -m shell -a 'echo devops | passwd --stdin devops'
172.25.254.20 | CHANGED | rc=0 >>
更改用户 devops 的密码 。
passwd:所有的身份验证令牌已经成功更新。
172.25.254.30 | CHANGED | rc=0 >>
更改用户 devops 的密码 。
passwd:所有的身份验证令牌已经成功更新。
172.25.254.10 | CHANGED | rc=0 >>
更改用户 devops 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[devops@mha ansible]$ ansible mysql -m shell -a 'echo "devops ALL=(ALL) NOPASSWD: ALL" > /etc/sudoer.d'
172.25.254.30 | CHANGED | rc=0 >>
172.25.254.20 | CHANGED | rc=0 >>
172.25.254.10 | CHANGED | rc=0 >>
[devops@mha ansible]$ exit
手动还原方式
mysql-node1---172.25.254.10
bash
#所有节点初始化数据
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
Shutting down MySQL... SUCCESS!
[root@mysql-node1 ~]# rm -rf /data/mysql/*
[root@mysql-node1 ~]# cat > /etc/my.cnf <<EOF
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
#不同主机server-id一定要根据实际情况做相应改变
server-id=10
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
default_authentication_plugin=mysql_native_password
log_slave_updates=ON
binlog_format=ROW
binlog_checksum=NONE
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
EOF
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
A temporary password is generated for root@localhost: 7K1Nep7X>LYw
mysql-node2---172.25.254.20
bash
[root@mysql-node2 ~]# /etc/init.d/mysqld stop
Shutting down MySQL.... SUCCESS!
[root@mysql-node2 ~]# rm -rf /data/mysql/*
[root@mysql-node2 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=20
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
default_authentication_plugin=mysql_native_password
log_slave_updates=ON
binlog_format=ROW
binlog_checksum=NONE
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
[root@mysql-node2 ~]# mysqld --user=mysql --initialize
A temporary password is generated for root@localhost: X9hm>lDF3qyr
mysql-node3---172.25.254.30
bash
[root@mysql-node3 ~]# /etc/init.d/mysqld stop
Shutting down MySQL.... SUCCESS!
[root@mysql-node3 ~]# rm -rf /data/mysql/*
[root@mysql-node3 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql
socket=/data/mysql/mysql.sock
symbolic-links=0
server-id=30
log-bin=mysql-bin
gtid_mode=ON
enforce-gtid-consistency=ON
default_authentication_plugin=mysql_native_password
log_slave_updates=ON
binlog_format=ROW
binlog_checksum=NONE
disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY"
[root@mysql-node3 ~]# mysqld --user=mysql --initialize
A temporary password is generated for root@localhost: +7)MF6%OtD6s
七、部署组复制
mysql-node1--172.25.254.10
bash
#设置所有mysql节点的解析
[root@mysql-node1 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.10 mysql-node1
172.25.254.20 mysql-node2
172.25.254.30 mysql-node3
[root@mysql-node1 ~]# cat >> /etc/my.cnf <<EOF
plugin_load_add='group_replication.so'
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address="172.25.254.10:33061" #其他两台主机一定要根据ip进行修改
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,172.25.254.30:33061"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
EOF
[root@mysql-node1 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node1.err'.
. SUCCESS!
#配置组复制
[root@mysql-node1 ~]# mysql -uroot -p'7K1Nep7X>LYw'
mysql> alter user root@localhost identified by 'yu';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
mysql> CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user', SOURCE_PASSWORD='yu' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> SHOW PLUGINS; #查看组复制插件是否激活
| group_replication | ACTIVE | GROUP REPLICATION | group_replication.so | GPL |
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='yu';
Query OK, 0 rows affected (1.50 sec)
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM performance_schema.replication_group_members;
#看到主机online表示成功

mysql-node2--172.25.254.20
bash
#设置所有mysql节点的解析
[root@mysql-node2 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.10 mysql-node1
172.25.254.20 mysql-node2
172.25.254.30 mysql-node3
[root@mysql-node2 ~]# cat >> /etc/my.cnf <<EOF
plugin_load_add='group_replication.so'
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address="172.25.254.20:33061"
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,172.25.254.30:33061"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
EOF
[root@mysql-node2 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node2.err'.
SUCCESS!
[root@mysql-node2 ~]# mysql -uroot -p'X9hm>lDF3qyr'
mysql> alter user root@localhost identified by 'yu';
Query OK, 0 rows affected (0.02 sec)
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
mysql> CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user',SOURCE_PASSWORD='yu' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='yu';
ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log. #出现此处报错可以初始化下master
mysql> reset master; #用过此命令解决以上报错
Query OK, 0 rows affected, 1 warning (0.01 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='yu';
Query OK, 0 rows affected (2.27 sec)
mysql> SELECT * FROM performance_schema.replication_group_members;
#看到主机online表示成功

msyql-node3--172.25.254.30
bash
#设置所有mysql节点的解析
[root@mysql-node3 ~]# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.10 mysql-node1
172.25.254.20 mysql-node2
172.25.254.30 mysql-node3
[root@mysql-node3 ~]# cat >> /etc/my.cnf <<EOF
plugin_load_add='group_replication.so'
group_replication_group_name="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
group_replication_start_on_boot=off
group_replication_local_address="172.25.254.30:33061"
group_replication_group_seeds="172.25.254.10:33061,172.25.254.20:33061,172.25.254.30:33061"
group_replication_bootstrap_group=off
group_replication_single_primary_mode=OFF
EOF
[root@mysql-node3 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node3.err'.
SUCCESS!
[root@mysql-node3 ~]# mysql -uroot -p'+7)MF6%OtD6s'
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.3.0
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> alter user root@localhost identified by 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'yu';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT CONNECTION_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT BACKUP_ADMIN ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT GROUP_REPLICATION_STREAM ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
mysql> CHANGE REPLICATION SOURCE TO SOURCE_USER='rpl_user',SOURCE_PASSWORD='yu' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.02 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='yu';
ERROR 3092 (HY000): The server is not configured properly to be an active member of the group. Please see more details on error log. #出现此处报错可以初始化下master
mysql> reset master; #用过此命令解决以上报错
Query OK, 0 rows affected, 1 warning (0.02 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='yu';
Query OK, 0 rows affected (6.07 sec)
mysql> SELECT * FROM performance_schema.replication_group_members;
三台主机部署成功后的效果
均为online和primary

测试
bash
#测试所有节点是否可以执行读写并数据是否同步
#node3中
[root@mysql-node3 ~]# mysql -uroot -pyu
mysql> create database liouo;
Query OK, 1 row affected (0.01 sec)
mysql> create table liouo.userlist (
-> username varchar(10) primary key not null,
-> password varchar(50) not null
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> insert into liouo.userlist values ('user1','111');
Query OK, 1 row affected (0.03 sec)
#在node2中查看并插入新的数据
[root@mysql-node2 ~]# mysql -uroot -pyu
mysql> select * from liouo.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
+----------+----------+
1 row in set (0.00 sec)
mysql> insert into liouo.userlist values ('user2','222');
Query OK, 1 row affected (0.00 sec)
#在node1中查看并插入数据
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> select * from liouo.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
+----------+----------+
2 rows in set (0.00 sec)
mysql> insert into liouo.userlist values ('user3','333');
Query OK, 1 row affected (0.01 sec)
在node1、2、3中均可以看到以上数据

八、Mysqlrouter
MySQLrouter软件下载





bash
[root@mysqlrouter ~]# wget https://downloads.mysql.com/archives/get/p/41/file/mysql-router-community-8.4.7-1.el9.x86_64.rpm
安装mysqlrouter
bash
[root@mysqlrouter ~]# dnf install mysql-router-community-8.4.7-1.el9.x86_64.rpm -y
mysqlrouter配置文件
bash
[root@mysqlrouter ~]# rpm -qc mysql-router-community
/etc/logrotate.d/mysqlrouter #日志轮询及日志截断策略
/etc/mysqlrouter/mysqlrouter.conf #主配置文件
[root@mysqlrouter ~]# systemctl status mysqlrouter.service #启动脚本
配置mysqlrouter
bash
[root@mysqlrouter ~]# vim /etc/mysqlrouter/mysqlrouter.conf
[routing:ro]
bind_address = 0.0.0.0
bind_port = 7001
destinations = 172.25.254.10:3306,172.25.254.20:3306,172.25.254.30:3306
routing_strategy = round-robin
[routing:rw]
bind_address = 0.0.0.0
bind_port = 7002
destinations = 172.25.254.30:3306,172.25.254.20:3306,172.25.254.10:3306
routing_strategy = first-available
[root@mysqlrouter ~]# systemctl enable --now mysqlrouter.service
Created symlink /etc/systemd/system/multi-user.target.wants/mysqlrouter.service → /usr/lib/systemd/system/mysqlrouter.service.
[root@mysqlrouter ~]# netstat -antlupe | grep mysql
tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 991 176991 39587/mysqlrouter
tcp 0 0 0.0.0.0:7002 0.0.0.0:* LISTEN 991 176009 39587/mysqlrouter
测试
bash
#在mysql节点的任意主机中添加root远程登录
[root@mysql-node1 ~]# mysql -uroot -pyu
mysql> CREATE USER root@'%' identified by 'yu';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT ALL ON *.* TO root@'%';
Query OK, 0 rows affected (0.00 sec)
[root@mysql-node1 ~]# mysql -uroot -plee -h172.25.254.10
mysql> quit
Bye
[root@mysql-node1 ~]# mysql -uroot -plee -h172.25.254.20
mysql> quit
Bye
[root@mysql-node1 ~]# mysql -uroot -plee -h172.25.254.30
mysql> quit
Bye
#查看调度效果
[root@mysql-node1 ~]# watch -n1 lsof -i :3306
[root@mysql-node2 ~]# watch -n1 lsof -i :3306
[root@mysql-node3 ~]# watch -n1 lsof -i :3306
可以使用mysqlnode1、2、3三台任意一台主机进行测试,这里使用另外一台客户端172.25.254.99进行测试
使用端口7001是轮询,效果如下
- 第一次测试

- 第二次测试

- 第三次测试

使用端口7002是最快相应,效果如下

九.实验中常遇到的问题及解决芳芳
问题1:源码编译时 make 失败,提示缺少 Boost 库
现象 :cmake 过程中报错 Could not find Boost。
原因 :未使用 -DWITH_BOOST=bundled 或系统中未安装 Boost。
解决 :在 cmake 命令中添加 -DWITH_BOOST=bundled,让 MySQL 源码自带的 boost 被使用。
问题2:初始化后临时密码无法登录
现象 :mysql -uroot -p 输入临时密码提示 Access denied。
原因 :密码中包含特殊字符(如 *cpw*U8whdXh),未正确转义。
解决 :使用单引号包裹密码,或先修改 .bash_history 再输入。建议直接复制粘贴并注意 * 符号。
问题3:从库 START SLAVE 后 Slave_IO_Running: Connecting 一直不变成 Yes
现象 :Last_IO_Error 为 error connecting to master ...。
可能原因与解决:
- 网络不通 →
ping测试,检查防火墙 - 复制用户权限不足 → 确保
GRANT REPLICATION SLAVE MASTER_LOG_FILE/MASTER_LOG_POS错误 → 重新在主库SHOW MASTER STATUSbind-address未监听外网 → 修改 my.cnf 中bind-address=0.0.0.0或注释掉
问题4:开启 GTID 后 START SLAVE 报错 Slave failed to initialize ...
现象 :ERROR 1872 或 Slave failed to initialize relay log info structure from the repository。
原因:从库之前有基于 binlog+position 的复制残留。
解决:
sql
STOP SLAVE;
RESET SLAVE ALL;
CHANGE MASTER TO MASTER_HOST=..., MASTER_AUTO_POSITION=1;
START SLAVE;
问题5:半同步复制中主库写入延迟变大(10秒)
现象 :INSERT 耗时 10 秒后才返回。
原因 :所有从库的 IO 线程停止,主库等待 rpl_semi_sync_master_timeout(默认 10000ms)超时后降级为异步。
解决:检查从库半同步插件是否激活、网络是否正常。可调整超时时间或确保至少一个从库正常。
问题6:MHA 检测失败,报 MySQL Replication Health is NOT OK!
现象 :masterha_check_repl 提示复制线程异常或 SSH 互信失败。
解决:
- 检查所有节点
SHOW SLAVE STATUS确保Slave_IO/SQL_Running均为 Yes - 配置 SSH 免密登录(包括 Manager 到各 Node 以及 Node 之间)
- 确保 MHA 管理用户(如
root@'%')在 master 上已创建且密码正确
问题7:MHA 手动切换时卡住或报 Can't locate MHA/NodeUtil.pm
现象:Perl 模块缺失。
解决 :在 Manager 和所有 Node 上安装 perl-CPAN 并通过 cpan 安装 Config::Tiny、Log::Dispatch、Mail::Sender、Parallel::ForkManager。并修改 NodeUtil.pm 适配 MySQL 8.0 版本解析。
问题8:组复制(MGR)启动时报 ERROR 3092
现象 :START GROUP_REPLICATION 失败,提示 server is not configured properly。
原因:新节点未重置 binlog,旧 GTID 执行记录冲突。
解决:
sql
RESET MASTER;
START GROUP_REPLICATION USER='rpl_user', PASSWORD='xxx';
问题9:MySQL Router 连接后一直返回同一个 server_id(没有轮询)
现象:读端口 7001 多次查询始终访问同一台 MySQL。
原因 :routing_strategy = first-available 被误用在读端口。
解决 :读端口使用 round-robin,写端口使用 first-available。
问题10:Ansible playbook 执行 mysqld --initialize 后无法获取临时密码
现象:初始化成功但密码被掩码,日志中不显示。
解决 :使用 -vv 详细输出并用 grep password 过滤,或预先将 initialize 的输出重定向到文件再 cat。
十.经验与建议
- 环境准备阶段:务必关闭防火墙或开放相应端口(3306、26379、33061、7001/2),否则各种连接问题难以排查。
- 日志为王 :MySQL 错误日志(默认
/data/mysql/*.err)和 MHA 日志(/etc/masterha/mha.log)是定位问题的第一手资料。 - 逐步验证 :每完成一个复制拓扑(如 GTID、半同步),先用
SHOW SLAVE STATUS确认关键字段,再插入测试数据。 - 备份与恢复技能 :使用
mysqldump+scp手动拉平数据是加入新从库的标准操作,务必掌握。 - 自动化思维:当需要重置三台以上节点时,Ansible 比手动操作效率提升百倍,建议多场景练习。