一、什么是MySQL
MySQL是一款开源的关系型数据库管理系统,它遵循SQL(结构化查询语言)标准,用于搞笑地组织、存储、查询和管理结构化数据。凭借其高性能、高可靠性、易用性以及低成本的优势,MySQL已成为web应用、电子商务、金融等各类企业业务系统的核心数据存储方案。
MySQL 集群(MySQL Cluster)本质是为了解决单节点 MySQL 的 性能瓶颈 (高并发)、可用性风险 (单点故障)和 数据可靠性(数据丢失)问题,通过多台服务器协同工作,将数据分散 / 复制存储、请求分散处理,最终实现:
高可用(HA):单个节点故障不影响整体服务;
高扩展(Scalability):可通过增加节点提升处理能力;
数据一致性:集群内数据保持同步(不同架构一致性级别不同)
二、MySQL的原理
MySQL采取经典的分层架构,其核心工作流程如下:
1.连接层
负责管理客户端连接,进行身份认证与权限校验
2.服务层
是MySQL的核心。负责SQL语句的解析、优化,并生成执行计划
3.存储引擎层
负责数据的实际存取,采用插件式架构。innoDB是MySQL5.5版本后的默认引擎,其关键特性包括:
(1)事务支持(ACID):确保数据操作的原子性、一致性、隔离性和持久性。
(2)行级锁与MVCC:提高高并发下的数据一致性与性能。
(3)崩溃恢复:通过Redo Log等机制保障数据安全
4.物理存储层
数据最终持久化于磁盘文件。其B+树索引结构查询效率稳定,能高效支持点查询与范围查询
简单来说就是你给"仓库管理员"(MySQL)下命令(SQL语句)找东西,它内部有一套严密的工作流程:
-
前台接待(连接层) :先核实你的身份(账号密码),看看你有没有权限进这个库房。指令
-
指令翻译(服务层):把你的需求(比如"找出去年所有订单")翻译、优化成最高效的搬运计划。
-
工人干活(存储引擎层) :真正的"搬货工人"。MySQL最厉害的"工人"叫InnoDB,它干活特别靠谱:
(1)支持事务(ACID) :比如你转账,它保证要么钱全转过去,要么一分不动,绝不会中间出错。 (2)行级锁 :只锁住正在处理的那一条数据,不影响其他人搬旁边的货,人多也不怕乱。 (3)崩溃恢复:万一仓库断电,重启后它能根据"工作日志"把没干完的活补上,数据不会丢
-
货物上架(物理存储层) :最终数据以文件形式存到硬盘上。为了快速查找,MySQL使用一种叫B+树的索引结构,就像书的目录,能让你在海量数据中瞬间定位目标。
三、在企业中怎么使用
在企业生产环境中,MySQL通常以集群形式部署,以满足高并发、高可用及海量数据的需求。核心实践包括:
1.高可用与读写分离:
通过主从复制(Master-Slave Replication) 架构,将读操作分流至从库,提升系统吞吐量。配合数据库代理(Database Proxy) 中间件,可实现自动的读写分离与故障转移。
2.数据容灾与扩展:
采用MySQL Group Replication(MGR) 等方案构建高可用集群,确保金融级数据一致性。当数据量增长时,通过分库分表(Sharding) 实现水平扩展。
3.云原生与HTAP:
越来越多的企业选择云数据库服务,利用其弹性伸缩、自动化运维等特性。同时,HTAP(混合事务/分析处理) 架构的兴起,使MySQL能同时高效处理事务与实时分析,满足复杂业务需求。
四、MySQL企业级实战
1.MySQL集群实战------>在服务器中的部署方法
在企业中 90%的服务器操作系统均为 Linux
Mysql 版本使用最多的是 Mysql5.7 和 Mysql8
在企业中对于 Mysql 的安装通常用源码编译的方式来进行

企业中为什么采用源码编译
预编译的二进制包为追求最大兼容性,通常采用保守的通用编译参数(如-O2优化级别)。源码编译则允许DBA针对特定CPU架构(如Intel Xeon/AMD EPYC)启用高级指令集(如AVX2/AVX-512),并采用更高级的优化选项(如-O3 -march=native)。这种"量体裁衣"式的优化,在计算密集型的高并发场景下,能有效提升数据库的吞吐量(TPS/QPS)并降低响应延迟。不过也需注意,这种性能提升并非总是质变,有观点认为在实际生产负载下,其与二进制包的QPS差距通常小于3%。
也就是说通用安装包为了能在各种电脑上运行,用的是"平均"水平的优化。源码编译则可以根据你服务器的具体"体质"(比如CPU型号)进行"一对一"的专属优化,把硬件的全部潜力都发挥出来
源码编译提供了高度的定制化能力。你可以精确地选择编译哪些组件,例如:
-
存储引擎 :只启用
InnoDB,禁用MyISAM、FEDERATED等非必需引擎。 -
字符集:只编译业务所需的字符集,减少资源开销。
-
功能插件 :按需集成或剔除特定功能,如自定义认证插件、审计插件等。
这种"按需定制"能有效减小二进制文件体积,精简运行时资源消耗,并减少潜在的攻击面
也就是说MySQL有很多功能,但你的业务可能只用到其中一部分。源码编译就像"自助餐",你可以只选自己需要的"菜"(比如只用InnoDB引擎),去掉用不上的,让数据库更轻便、更专注
且用别人编译好的包,你无法完全知道里面有没有"后门"或漏洞。源码编译能让你从源头把控代码,并进行额外的安全加固,满足金融、政务等行业的严格合规要求
数据库出问题的时候,如果只知道怎么用,不知道它内部怎么运作,排查起来会很困难。源码编译的过程能让你对MySQL的构造了如指掌,遇到棘手Bug时,甚至能结合源码进行分析,快速定位问题根源
对于大公司,有成百上千台服务器要装MySQL,不可能一台台去编译。他们会先在一台机器上编译、测试好,然后把编译好的成果打包成标准化的安装包(如RPM)或容器镜像,再一键部署到所有服务器上,保证每台机器的环境完全一致
(1)下载安装包
bash
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-8.3.0.tar.gz
(2)源码编译
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 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_SSL=system -DWITH_DEBUG=OFF
[root@mysql-node1 build]# make
#源码编译参数详解
root@mysql_node1 mysql-8.3.0# mkdir build #建立编译目录
root@mysql_node1 mysql-8.3.0# cmake3 .. \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ #指定安装路径
-DMYSQL_DATADIR=/data/mysql \ #指定数据目录
-DSYSTEMD=ON \ # 启用 systemd 支持(核心参数)
-DSYSTEMD_SERVICE_DIR=/usr/lib/systemd/system \ # systemd 服务文件安装路径
-DMYSQL_UNIX_ADDR=/data/mysql/mysql.sock \ #指定套接字文件
-DWITH_INNOBASE_STORAGE_ENGINE=1 \ #指定启用INNODB存储引擎,默认用myisam
-DWITH_EXTRA_CHARSETS=all \ #扩展字符集
-DDEFAULT_CHARSET=utf8mb4 \ #指定默认字符集
-DDEFAULT_COLLATION=utf8mb4_unicode_ci \ #指定默认校验字符集
-DWITH_SSL=system \ #指定MySQL 使用系统已安装的 SSL 库
-DWITH_BOOST=bundled \ #指定使用 MySQL 源码包中内置的Boost库
-DWITH_DEBUG=OFF
bash
[root@mysql_node1 build]# make -j2 #-j2 表示有几个核心就跑几个进程
(3)部署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 ~]# vim /etc/my.cnf
[mysqld]
datadir=/data/mysql #指定数据目录
socket=/data/mysql/mysql.sock #指定套接字
symbolic-links=0 #数据只能存放到数据目录中,禁止链接到数据目录
(4)MySQL数据结构初始化
bash
[root@mysql-node1 ~]# mysqld --initialize --user=mysql

(5)启动MySQL
bash
#采用mysql自带init脚本启动
[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
#采用自编写systemd启动脚本启动
[root@mysql-node2 ~]# vim /lib/systemd/system/mysqld.service
[Unit]
Description=MySQL 8.3 Database Server
Documentation=man:mysqld(8)
After=network.target syslog.target
[Service]
Type=notify
User=mysql
Group=mysql
ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
ExecReload=/usr/local/mysql/bin/mysqladmin --defaults-file=/etc/my.cnf shutdown
TimeoutSec=300
PrivateTmp=true
LimitNOFILE=65535
LimitNPROC=65535
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
[root@mysql-node2 ~]# systemctl daemon-reload
[root@mysql-node2 ~]# systemctl enable --now mysqld.service
(6)MySQL安全初始化
bash
[root@node10 ~]# 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 PLUGIN 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 plugin?
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.
测试

2.MySQL集群实战------>主从复制
MySQL主从复制是一种异步的数据复制机制。它允许将一台MySQL主库(Master)上的数据变更,自动、实时地同步到一台或多台从库(Slave/Replica)上。其核心是实现数据的多副本存储,为构建高可用、高性能的数据库架构奠定基础。
主从复制就是给你的数据库找个"影子分身"。主库(Master)是"真身",负责处理所有写入操作;从库(Slave)是"影子",实时同步主库的数据变化。这样,主库万一出问题,从库能立刻顶上,业务不停摆。
主从复制是企业级数据库架构的基石,其核心价值体现在四个方面:
-
高可用容灾:主库故障时可快速切换至从库,避免单点故障导致服务不可用。
-
读写分离与水平扩展:写操作集中于主库,读操作分散到多个从库,突破单节点的性能瓶颈。
-
数据备份与离线分析:从库可用于执行备份、报表统计等任务,避免占用主库资源。
-
异地多活:跨地域部署从库,实现就近访问与地域级容灾
也就是
-
防宕机:主库"罢工"了,从库能秒变主库,业务不中断。
-
减压力:把"读"数据的活儿全部分给从库,主库专心处理"写"请求,系统整体扛得住更大的流量。
-
保数据:从库是实时热备,误删数据或硬盘坏了,也能快速恢复。
-
做分析:在从库上跑复杂的报表统计,不影响主库的正常业务
(1)编写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~3 ~]# /etc/init.d/mysqld restart
(2)建立同步时需要用到的数据库账号
bash
[root@mysql-node1 ~]# mysql -uroot -plee
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 lee@'%' identified with mysql_native_password by 'lee'; #建立用户
Query OK, 0 rows affected (0.04 sec)
mysql> select User from mysql.user;
+------------------+
| User |
+------------------+
| lee |
| mysql.infoschema |
| mysql.session |
| mysql.sys |
| root |
+------------------+
5 rows in set (0.00 sec)
mysql> GRANT replication slave ON *.* to lee@'%'; #给用户授权
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW GRANTS FOR lee@'%';
+---------------------------------------------+
| Grants for lee@% |
+---------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO `lee`@`%` |
+---------------------------------------------+
1 row in set (0.00 sec)
#在其他主机中
[root@mysql-node2 ~]# mysql -ulee -plee -h172.25.254.10
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 9
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> quit
(3)配置数据库一主一从
bash
#在master中查看日志文件名称及id
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 659 | | | |
+------------------+----------+--------------+------------------+-------------------+
#在slave主机中
[root@mysql-node2 ~]# mysql -uroot -plee
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='lee',MASTER_PASSWORD='lee',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=659;
Query OK, 0 rows affected, 8 warnings (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.03 sec)
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.03 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: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 659
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 #通过同步过来的数据做日志回访成功
(4)测试
bash
[root@mysql-node1 ~]# mysql -uroot -lee #在master中建立库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
mysql> create database timinglee;
Query OK, 1 row affected (0.00 sec)
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| timinglee |
+--------------------+
5 rows in set (0.00 sec)
[root@mysql-node2 ~]# mysql -uroot -plee #在slave主机中可以实现数据同步
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| timinglee |
+--------------------+
5 rows in set (0.00 sec)
(5)向当前一主一从中加入新的数据库
bash
#模拟一主一从中已经存在数据情况
[root@mysql-node1 ~]# mysql -uroot -plee
mysql> CREATE TABLE timinglee.userlist (
-> name VARCHAR(10) not null,
-> pass VARCHAR(50) not null
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO timinglee.userlist values ('user1','123');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
+-------+------+
1 row in set (0.01 sec)
#加入新从库时需要手动拉平数据
[root@mysql-node1 ~]# mysqldump -uroot -p timinglee > timinglee.sql
[root@mysql-node1 ~]# scp timinglee.sql root@172.25.254.30:/root/
[root@mysql-node3 ~]# mysql -uroot -plee -e "create database timinglee;"
[root@mysql-node3 ~]# mysql -uroot -plee timinglee < timinglee.sql
[root@mysql-node3 ~]# mysql -uroot -plee
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
+-------+------+
1 row in set (0.00 sec)
(6)将新库加入主从结构中
bash
#在master中查看日志的id
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 1415 | | | |
+------------------+----------+--------------+------------------+-------------------+
[root@mysql-node3 ~]# mysql -uroot -plee
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10',MASTER_USER='lee',MASTER_PASSWORD='lee',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=1415;
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.04 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: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 1415
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
(7)测试一主两从
bash
#在master中建立数据
mysql> INSERT INTO timinglee.userlist values ('user2','123');
#在新加入的slave中查看信息
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
| user2 | 123 |
+-------+------+
2 rows in set (0.00 sec)
3.MySQL集群实战------>MySQL主从架构中的使用技巧及优化
(1)延迟复制
延迟复制(Delayed Replication)是MySQL从5.6版本开始支持的一种特殊复制策略。它允许从库(Replica)故意滞后于主库(Source)一段指定的时间再执行事务。其默认延迟时间为0秒。
就像是给你的数据库"影子"装了个定时器 。主库(Master)每做一次数据变更,从库(Slave)不是立即同步,而是故意等上一段时间(比如1小时)再执行
延迟复制是企业数据安全防线的关键补充,其核心价值主要体现在以下三点:
-
防范人为失误(核心价值) :提供"数据后悔药"。当主库发生误操作时,可将延迟从库回退到错误发生前的状态,实现快速、精准的数据恢复。
-
模拟与测试:可用于模拟生产环境可能出现的复制延迟场景,以便测试应用程序在延迟情况下的行为与稳定性。
-
历史数据查询:可将从库配置为长延迟(如一周),用于回溯查看数据库过去某个时间点的状态,而无需从备份中恢复
它的核心价值就是给你一个 "后悔药" 。万一有人手滑执行了DELETE或DROP之类的误操作,你可以立刻让延迟从库在误操作前的那个时间点停下来,然后把数据抢救回来。这比从备份文件里恢复数据要快得多、简单得多
配置
bash
#在指定需要延迟同步的slave主机中,如果主机中安装数据库的版本是8以上
mysql> STOP REPLICA;
mysql> CHANGE REPLICATION SOURCE TO SOURCE_DELAY=60;
mysql> START REPLICA;
[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> delete from timinglee.userlist where name='user1';
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user2 | 123 |
+-------+------+
1 row in set (0.00 sec)
#在未被延迟的slave数据库中查看是否数据操作动作被同步
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user2 | 123 |
+-------+------+
1 row in set (0.00 sec)
#在被设定延迟复制的主机中查看动作是否被同步
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user1 | 123 |
| user2 | 123 |
+-------+------+
2 rows in set (0.00 sec)
#等待延迟时间过后再次查看
mysql> select * from timinglee.userlist;
+-------+------+
| name | pass |
+-------+------+
| user2 | 123 |
+-------+------+
1 row in set (0.00 sec)
(2)慢查询日志
慢查询日志(Slow Query Log)是MySQL内置的一种日志机制,用于记录执行时间超过指定阈值(long_query_time)的SQL语句。它是数据库性能诊断与SQL优化的核心工具,为开发者和DBA提供了定位低效查询、分析性能瓶颈的真实数据依据。
就像是数据库的 "病历本" 。你的数据库平时跑得好好的,突然有一天变慢了,业务方一直催,你看着CPU飙高却不知道是哪个SQL惹的祸。这时候,慢查询日志就能帮你------它会自动记录下所有"跑得慢"的SQL语句,告诉你到底是哪条SQL"生病"了
它的工作原理很简单------你给MySQL设定一个时间门槛 (比如1秒),任何查询只要执行时间超过这个门槛 ,MySQL就会在它执行完成后,把这条SQL连同它的"体检报告"(执行了多久、锁了多久、扫了多少行数据等)一起记到日志文件里。需要注意的是,慢查询日志默认是关闭的,需要手动开启
日志内容示例
bash
# Time: 2021-05-13T17:38:03.687811+08:00
# User@Host: root[root] @ [192.168.85.0] Id: 2604943
# Query_time: 1.099889 Lock_time: 0.000144 Rows_sent: 39 Rows_examined: 45305
SET timestamp=1620898683;
SELECT * FROM test_table WHERE col_name LIKE '%测试%';
配置
bash
#慢查询日志是否开启
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.03 sec)
#开启慢查询日志
mysql> SET GLOBAL slow_query_log=ON;
Query OK, 0 rows affected (0.03 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.01 sec)
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> select sleep (3); #不会生成慢查询日志
+-----------+
| sleep (3) |
+-----------+
| 0 |
+-----------+
1 row in set (3.00 sec)
mysql> select sleep (4);
+-----------+
| sleep (4) |
+-----------+
| 0 |
+-----------+
1 row in set (4.00 sec)
[root@mysql-node1 ~]# cat /data/mysql/mysql-node1-slow.log
/usr/local/mysql/bin/mysqld, Version: 8.3.0 (Source distribution). started with:
Tcp port: 3306 Unix socket: /data/mysql/mysql.sock
Time Id Command Argument
# Time: 2026-02-27T02:04:39.297189Z
# User@Host: root[root] @ localhost [] Id: 10
# Query_time: 4.000424 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 1
SET timestamp=1772157875;
select sleep (4);
(3)gtid模式
GTID(Global Transaction Identifier,全局事务标识符)是MySQL 5.6版本引入的一种复制机制。它为每一个在源服务器上提交的事务 生成一个全局唯一的标识符。GTID的格式为 server_uuid:transaction_id,例如 3E11FA47-71CA-11E1-9E33-C80AA9429562:23。它从根本上改变了复制定位方式,从基于文件名和位置(Position) 转变为基于事务,从而简化了复制管理。
就像给数据库里的每一笔"交易"发了一个全球唯一的身份证号 。以前主从复制靠的是"第几个文件、第几行"来定位,就像用"第3本书、第25页第3行"来找内容,换本书就乱了。有了GTID,每个事务都有一个独一无二的ID,不管在哪台服务器上,通过这个ID就能精确找到它,再也不用担心搞混了。
GTID的生命周期遵循以下步骤:
-
分配:事务在源服务器上提交时,会被分配一个GTID。
-
持久化 :GTID作为
Gtid_log_event,原子性地写入源服务器的二进制日志(Binlog)中。 -
传输:从库的I/O线程将包含GTID的Binlog事件传输到本地的中继日志(Relay Log)。
-
应用 :从库的SQL线程读取Relay Log,并检查该GTID是否已在
gtid_executed集合中。 -
幂等性保证:
-
如果GTID不存在 ,则执行该事务,并将其加入
gtid_executed集合。 -
如果GTID已存在,则自动跳过该事务。
-
这个机制确保了同一个GTID的事务在同一个从库上只会被应用一次,从根本上避免了因重复执行导致的数据不一致
配置
bash
#在master和slave中默认gtid模式是未开启的
mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name | Value |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | OFF |
| gtid_executed | |
| gtid_executed_compression_period | 0 |
| gtid_mode | OFF |
| gtid_next | AUTOMATIC |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-----------+
9 rows in set (0.01 sec)
#在所有主机中加入参数
[root@mysql-node1~3 ~]# vim /etc/my.cnf
gtid_mode=ON
enforce-gtid-consistency=ON
[root@mysql-node1~3 ~]# /etc/init.d/mysqld restart
#在三台主机中分别查看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.00 sec)
#在从库中停止slave功能;
mysql> stop slave;
mysql> CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='lee', MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;
mysql> start slave ;
mysql> SHOW SLAVE STATUS \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 172.25.254.10
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 158
Relay_Log_File: mysql-node2-relay-bin.000002
Relay_Log_Pos: 375
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 158
Relay_Log_Space: 592
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 10
Master_UUID: be64e358-12b4-11f1-88cc-000c29f4a60c
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Replica has read all relay log; waiting for more updates
Master_Retry_Count: 10
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 1
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
Master_public_key_path:
Get_master_public_key: 0
Network_Namespace:
1 row in set, 1 warning (0.00 sec)
(4)多线程回放
多线程回放(Multi-Threaded Replay),即MySQL的并行复制(Parallel Replication) ,是指从库(Replica)使用多个工作线程(Worker Threads) 并行地应用(回放)中继日志(Relay Log)中的事务。其核心目标是通过提升从库的日志应用速度,减少主从延迟(Replication Lag),从而保障数据同步的实时性和系统的高可用性。
多线程回放,就是给从库的"执行者"(SQL线程)找了一群帮手 。以前从库只有一个SQL线程在"吭哧吭哧"地干活,主库却有一堆线程并发写入,导致从库总是跟不上主库的节奏,产生延迟。现在从库可以开多个线程,把原本必须串行执行的工作,变成并行执行,大大加快了数据同步的速度。
在传统的主从复制中,从库只有一个SQL线程串行回放日志。当主库写入压力较大时,从库的SQL线程会成为性能瓶颈,导致主从延迟不断增大。主从延迟会带来两大核心问题:
-
数据一致性受损:在读写分离架构下,业务可能读到旧数据。
-
高可用性风险:在进行主从切换时,要么等待延迟恢复而影响服务可用性,要么直接切换导致数据丢失。
说白了就是为了解决"主从延迟"这个老大难问题。主库上轰轰烈烈地并行写入,从库却只能"单线程"地挨个执行,这就像单行道遇到了高峰期,必然拥堵。多线程回放将"单行道"拓宽成"多车道",让从库的同步速度能追上主库,保证业务读到的是最新数据,也避免了主从切换时可能丢数据
多线程回放的核心难题是:怎么确保多个线程同时执行不同的事务不会出错? 答案很简单:只让那些互不干扰、没有锁冲突的事务并行执行。
MySQL各个版本通过不同的技术手段来识别这些"互不干扰"的事务:
-
MySQL 5.6(基于库) :简单粗暴。只要操作的是不同的数据库(Schema),就认为它们互不干扰,可以并行。缺点是如果所有业务都在一个库里,就完全无法并行。
-
MySQL 5.7(基于组提交) :更精细了。如果两个事务在主库上能同时进入准备(Prepare)阶段 ,说明它们之间没有锁冲突。MySQL会为这些事务打上相同的"逻辑时间戳"标记(
last_committed),从库看到相同标记的事务就并行执行。这打破了"基于库"的限制,大幅提升了并行度。 -
MySQL 8.0(基于WriteSet) :更进一步。它通过分析事务实际修改了哪些数据行(WriteSet) 来判断冲突。只要两个事务修改的数据行没有交集,就能并行。即使在主库并发不高的情况下,也能挖掘出更多的并行机会。
配置
bash
#在slave主机中默认回方日志时使用单线程回放
mysql> show processlist;

bash
#开启多线程回放日志(在slave主中)
[root@mysql-node2 ~]# vim /etc/my.cnf
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
relay_log_recovery=ON
[root@mysql-node2 ~]# /etc/init.d/mysqld restart
#查看更改生效信息
mysql> show processlist;

(5)半同步模式
半同步复制(Semisynchronous Replication)是MySQL 5.5版本引入的一种复制模式。它介于异步复制 和全同步复制 之间。其核心机制是:主库在提交一个事务时,会阻塞并等待,直到至少一个从库确认已收到并记录了该事务的所有二进制日志(Binlog)事件。
在默认的异步复制里,主库(Master)写完自己的"账本"(Binlog)就完事了,根本不管从库(Slave)有没有收到。这就好比发微信,你消息发出去了,但对方有没有收到、有没有看,你完全不知道。如果这时候你手机坏了,对方可能就永远错过这条消息了。
半同步复制则要求:主库必须等至少一个从库回复"收到了,已记下",才会正式提交事务,并把"成功"的结果返回给客户端 。这就像是发微信改成了发挂号信,必须等对方签收了,你这边才算完事。
半同步复制旨在解决异步复制的数据安全性 问题。它通过增加一个同步确认步骤,确保了已提交事务的持久性------即事务不仅在主库上提交,也已传输到至少一个从库的中继日志(Relay Log)中。这极大地降低了因主库故障导致已提交事务丢失的风险
也就是解决了异步复制下,主库突然宕机可能丢数据的核心痛点。
在异步模式下,如果主库刚写完"账本"还没来得及发给从库就挂了,那这笔交易就彻底丢了。半同步复制保证了只要客户端收到"成功"的返回,这笔数据就至少存在于两台机器上(主库和至少一个从库)。主库再挂,数据也不会丢。
半同步复制在异步复制的基础上,增加了一个同步点。其工作流程如下:
-
日志写入:主库将事务事件写入其二进制日志(Binlog)。
-
传输与等待 :主库的
dump线程将Binlog事件发送给从库,随后事务提交线程进入阻塞等待状态,等待从库的确认(ACK)。 -
确认与回复 :从库的I/O线程接收到事件后,将其写入中继日志(Relay Log)并刷新到磁盘,随后向主库回复一个确认消息。
-
提交与返回:主库收到ACK后,才将事务提交到存储引擎,并向客户端返回成功。
配置
bash
#在master主机中操作
[root@mysql-node1~3 ~]# 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;
#在slave主机中
[root@mysql-node1~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_master | ACTIVE |
+----------------------+---------------+
1 row in set (0.00 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 | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| 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 | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
#测试:
#在主库中
mysql> create database timinglee;
Query OK, 1 row affected (10.01 sec) #有等待ack时间
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)
#模拟ack故障 在所有slave主机中
mysql> STOP SLAVE IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.00 sec)
#在主库写入数据
mysql> INSERT INTO timinglee.userlist values ('user3','123');
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 | 0 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 2 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
14 rows in set (0.00 sec)
#恢复故障 在所有slave主机中
mysql> start SLAVE IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.00 sec)
4.MySQL集群实战------>Mysql-MHA高可用集群
MHA(Master High Availability)是一套由日本DeNA公司开发的开源MySQL高可用性解决方案。它专为MySQL主从复制架构设计,通过自动化监控和故障转移,在主库发生故障时,能在10-30秒内自动完成从库的选举与提升,最大程度保证数据一致性,实现服务的高可用性。
也就是它专门负责盯着主库(Master),一旦主库宕机或不可用,MHA会自动 从一堆从库(Slave)里挑出一个数据最新的,把它提升为新的主库,然后把其他从库都指向这个新主库。整个切换过程最快10-30秒就能完成,对上层应用来说几乎是"无感"的。
MHA由两部分组成
-
MHA Manager(管理节点):中央控制节点,负责监控集群中所有MySQL节点的健康状况,并在故障发生时协调故障转移流程。安装在独立的管理服务器上。它负责监控所有MySQL节点的状态,做出"谁来当新主库"的决策,并指挥整个切换过程。
-
MHA Node(数据节点):运行在每个MySQL节点上的代理程序,用于接收并执行Manager的指令。安装在每一台MySQL服务器上。它负责执行Manager下达的具体指令,比如应用日志、执行切换等。
MHA的故障转移流程主要包括以下几个步骤:
-
监控与故障检测:Manager通过心跳机制持续监控主库状态。
-
选举新主库 :从所有从库中,选择数据最为完整(复制延迟最小) 的一个作为新主库的候选者。
-
数据补偿 :MHA会尝试从故障主库获取最后的Binlog,并与其他从库的Relay Log进行对比,通过
apply_diff_relay_logs等机制,将差异的数据同步到新主库上,最大程度地保证数据一致性。 -
执行切换:将候选从库提升为新主库,并让其他从库指向新主库,完成复制拓扑的重构。
MHA是一个成熟、稳定、轻量级 的MySQL高可用解决方案。它通过自动化故障转移,有效解决了主从架构中主库单点故障的问题。虽然存在Manager单点、配置复杂等局限,但对于希望以较低成本实现MySQL高可用的企业来说,MHA依然是经过大量实践检验的可靠选择。在选型时,建议根据自身对数据一致性(RPO)、恢复时间(RTO)、技术栈和运维能力的综合要求来做决策。
1.准备工作
bash
#重新初始化数据
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
[root@mysql-node1 ~]# rm -fr /data/mysql/*
[root@mysql-node1 ~]# mysqld --initialize --user mysql
[root@mysql-node1 ~]# /etc/init.d/mysqld start
Starting MySQL.Logging to '/data/mysql/mysql-node1.err'.
SUCCESS!
[root@mysql-node1 ~]# mysql_secure_installation
[root@mysql-node1 ~]# mysql -uroot -plee -e "create user lee@'%' identified with mysql_native_password by 'lee';"
[root@mysql-node1 ~]# mysql -uroot -plee -e "GRANT replication slave ON *.* to lee@'%';"
[root@mysql-node1 ~]# mysql -uroot -plee -e "show master status;"
+------------------+----------+--------------+------------------+------------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+------------------------------------------+
| mysql-bin.000002 | 1468 | | | b9652041-19c7-11f1-a4c3-000c29f4a60c:1-5 |
+------------------+----------+--------------+------------------+------------------------------------------+
#重新配置主从 在slave主机中
[root@mysql-node2 ~]# mysql -uroot -plee -e "CHANGE MASTER TO MASTER_HOST='172.25.254.10', MASTER_USER='lee', MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;"
[root@mysql-node2 ~]# mysql -uroot -plee -e "start slave;"
[root@mysql-node2 ~]# mysql -uroot -plee -e "show slave status\G;"
(1)在所有主机中安装MHA相应软件
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 ~]# perl -MConfig::Tiny -e 'print "OK\n"'
OK
[root@mha ~]# perl -MLog::Dispatch -e 'print "OK\n"'
OK
[root@mha ~]# 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@mha ~]# perl -MParallel::ForkManager -e 'print "OK\n"'
OK
#在mha节点
[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
#在所有mysql节点
[root@mha MHA-7]# rpm -ivh mha4mysql-node-0.58-0.el7.centos.noarch.rpm --nodeps
(2)在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 ########################################
(3)修改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;
}
(4)建立MHA远程登陆用户
bash
#在master主机中
mysql> create user root@'%' identified with mysql_native_password by 'lee';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT ALL ON *.* TO root@'%' ;
Query OK, 0 rows affected (0.00 sec)
(5)生成MHA-manager的配置文件模板
bash
[root@mha mha4mysql-manager-0.58]# mkdir /etc/masterha/ -p
[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
(6)修改配置文件
bash
[root@mha mha4mysql-manager-0.58]# vim /etc/masterha/app1.cnf
[server default]
user=root
password=lee
ssh_user=root
repl_user=lee
repl_password=lee
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/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
(7)检测环境
bash
[root@mha mha4mysql-manager-0.58]# masterha_check_ssh --conf=/etc/masterha/app1.cnf
Fri Feb 27 16:23:20 2026 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Fri Feb 27 16:23:20 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Fri Feb 27 16:23:20 2026 - [info] Reading server configuration from /etc/masterha/app1.cnf..
Fri Feb 27 16:23:20 2026 - [info] Starting SSH connection tests..
Fri Feb 27 16:23:21 2026 - [debug]
Fri Feb 27 16:23:20 2026 - [debug] Connecting via SSH from root@172.25.254.10(172.25.254.10:22) to root@172.25.254.20(172.25.254.20:22)..
Fri Feb 27 16:23:20 2026 - [debug] ok.
Fri Feb 27 16:23:20 2026 - [debug] Connecting via SSH from root@172.25.254.10(172.25.254.10:22) to root@172.25.254.30(172.25.254.30:22)..
Fri Feb 27 16:23:20 2026 - [debug] ok.
Fri Feb 27 16:23:21 2026 - [debug]
Fri Feb 27 16:23:20 2026 - [debug] Connecting via SSH from root@172.25.254.20(172.25.254.20:22) to root@172.25.254.10(172.25.254.10:22)..
Fri Feb 27 16:23:21 2026 - [debug] ok.
Fri Feb 27 16:23:21 2026 - [debug] Connecting via SSH from root@172.25.254.20(172.25.254.20:22) to root@172.25.254.30(172.25.254.30:22)..
Fri Feb 27 16:23:21 2026 - [debug] ok.
Fri Feb 27 16:23:22 2026 - [debug]
Fri Feb 27 16:23:21 2026 - [debug] Connecting via SSH from root@172.25.254.30(172.25.254.30:22) to root@172.25.254.10(172.25.254.10:22)..
Fri Feb 27 16:23:21 2026 - [debug] ok.
Fri Feb 27 16:23:21 2026 - [debug] Connecting via SSH from root@172.25.254.30(172.25.254.30:22) to root@172.25.254.20(172.25.254.20:22)..
Fri Feb 27 16:23:21 2026 - [debug] ok.
Fri Feb 27 16:23:22 2026 - [info] All SSH connection tests passed successfully.
Use of uninitialized value in exit at /usr/bin/masterha_check_ssh line 44.
[root@mha mha4mysql-manager-0.58]# masterha_check_repl --conf=/etc/masterha/app1.cnf
Fri Feb 27 16:23:50 2026 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Fri Feb 27 16:23:50 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Fri Feb 27 16:23:50 2026 - [info] Reading server configuration from /etc/masterha/app1.cnf..
Fri Feb 27 16:23:50 2026 - [info] MHA::MasterMonitor version 0.58.
Fri Feb 27 16:23:51 2026 - [info] GTID failover mode = 1
Fri Feb 27 16:23:51 2026 - [info] Dead Servers:
Fri Feb 27 16:23:51 2026 - [info] Alive Servers:
Fri Feb 27 16:23:51 2026 - [info] 172.25.254.10(172.25.254.10:3306)
Fri Feb 27 16:23:51 2026 - [info] 172.25.254.20(172.25.254.20:3306)
Fri Feb 27 16:23:51 2026 - [info] 172.25.254.30(172.25.254.30:3306)
Fri Feb 27 16:23:51 2026 - [info] Alive Slaves:
Fri Feb 27 16:23:51 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Fri Feb 27 16:23:51 2026 - [info] GTID ON
Fri Feb 27 16:23:51 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Fri Feb 27 16:23:51 2026 - [info] Primary candidate for the new Master (candidate_master is set)
Fri Feb 27 16:23:51 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Fri Feb 27 16:23:51 2026 - [info] GTID ON
Fri Feb 27 16:23:51 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Fri Feb 27 16:23:51 2026 - [info] Not candidate for the new Master (no_master is set)
Fri Feb 27 16:23:51 2026 - [info] Current Alive Master: 172.25.254.10(172.25.254.10:3306)
Fri Feb 27 16:23:51 2026 - [info] Checking slave configurations..
Fri Feb 27 16:23:51 2026 - [info] read_only=1 is not set on slave 172.25.254.20(172.25.254.20:3306).
Fri Feb 27 16:23:51 2026 - [info] read_only=1 is not set on slave 172.25.254.30(172.25.254.30:3306).
Fri Feb 27 16:23:51 2026 - [info] Checking replication filtering settings..
Fri Feb 27 16:23:51 2026 - [info] binlog_do_db= , binlog_ignore_db=
Fri Feb 27 16:23:51 2026 - [info] Replication filtering check ok.
Fri Feb 27 16:23:51 2026 - [info] GTID (with auto-pos) is supported. Skipping all SSH and Node package checking.
Fri Feb 27 16:23:51 2026 - [info] Checking SSH publickey authentication settings on the current master..
Fri Feb 27 16:23:51 2026 - [info] HealthCheck: SSH to 172.25.254.10 is reachable.
Fri Feb 27 16:23:51 2026 - [info]
172.25.254.10(172.25.254.10:3306) (current master)
+--172.25.254.20(172.25.254.20:3306)
+--172.25.254.30(172.25.254.30:3306)
Fri Feb 27 16:23:51 2026 - [info] Checking replication health on 172.25.254.20..
Fri Feb 27 16:23:51 2026 - [info] ok.
Fri Feb 27 16:23:51 2026 - [info] Checking replication health on 172.25.254.30..
Fri Feb 27 16:23:51 2026 - [info] ok.
Fri Feb 27 16:23:51 2026 - [warning] master_ip_failover_script is not defined.
Fri Feb 27 16:23:51 2026 - [warning] shutdown_script is not defined.
Fri Feb 27 16:23:51 2026 - [info] Got exit code 0 (Not master dead).
MySQL Replication Health is OK.
(8)在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
2.集群切换操作
手动切换------master无故障切换
bash
#默认状态
[root@mysql-node2 ~]# mysql -uroot -plee -e "show slave status\G;" | head -n 10
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: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1968
Relay_Log_File: mysql-node2-relay-bin.000002
Relay_Log_Pos: 2185
[root@mysql-node3 ~]# mysql -uroot -plee -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: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 1968
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 2185
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
[root@mysql-node3 ~]#
#执行切换,把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
Sat Mar 7 10:21:01 2026 - [info] MHA::MasterRotate version 0.58.
Sat Mar 7 10:21:01 2026 - [info] Starting online master switch..
Sat Mar 7 10:21:01 2026 - [info]
Sat Mar 7 10:21:01 2026 - [info] * Phase 1: Configuration Check Phase..
Sat Mar 7 10:21:01 2026 - [info]
Sat Mar 7 10:21:01 2026 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Sat Mar 7 10:21:01 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Sat Mar 7 10:21:01 2026 - [info] Reading server configuration from /etc/masterha/app1.cnf..
Sat Mar 7 10:21:02 2026 - [info] GTID failover mode = 1
Sat Mar 7 10:21:02 2026 - [info] Current Alive Master: 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:21:02 2026 - [info] Alive Slaves:
Sat Mar 7 10:21:02 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:21:02 2026 - [info] GTID ON
Sat Mar 7 10:21:02 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:21:02 2026 - [info] Primary candidate for the new Master (candidate_master is set)
Sat Mar 7 10:21:02 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:21:02 2026 - [info] GTID ON
Sat Mar 7 10:21:02 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:21:02 2026 - [info] Not candidate for the new Master (no_master is set)
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 #输入内容
Sat Mar 7 10:21:28 2026 - [info] Executing FLUSH NO_WRITE_TO_BINLOG TABLES. This may take long time..
Sat Mar 7 10:21:28 2026 - [info] ok.
Sat Mar 7 10:21:28 2026 - [info] Checking MHA is not monitoring or doing failover..
Sat Mar 7 10:21:28 2026 - [info] Checking replication health on 172.25.254.20..
Sat Mar 7 10:21:28 2026 - [info] ok.
Sat Mar 7 10:21:28 2026 - [info] Checking replication health on 172.25.254.30..
Sat Mar 7 10:21:28 2026 - [info] ok.
Sat Mar 7 10:21:28 2026 - [info] 172.25.254.20 can be new master.
Sat Mar 7 10:21:28 2026 - [info]
From:
172.25.254.10(172.25.254.10:3306) (current master)
+--172.25.254.20(172.25.254.20:3306)
+--172.25.254.30(172.25.254.30:3306)
To:
172.25.254.20(172.25.254.20:3306) (new master)
+--172.25.254.30(172.25.254.30:3306)
+--172.25.254.10(172.25.254.10:3306)
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 10:21:34 2026 - [info] Checking whether 172.25.254.20(172.25.254.20:3306) is ok for the new master..
Sat Mar 7 10:21:34 2026 - [info] ok.
Sat Mar 7 10:21:34 2026 - [info] 172.25.254.10(172.25.254.10:3306): SHOW SLAVE STATUS returned empty result. To check replication filtering rules, temporarily executing CHANGE MASTER to a dummy host.
Sat Mar 7 10:21:34 2026 - [info] 172.25.254.10(172.25.254.10:3306): Resetting slave pointing to the dummy host.
Sat Mar 7 10:21:34 2026 - [info] ** Phase 1: Configuration Check Phase completed.
Sat Mar 7 10:21:34 2026 - [info]
Sat Mar 7 10:21:34 2026 - [info] * Phase 2: Rejecting updates Phase..
Sat Mar 7 10:21:34 2026 - [info]
Sat Mar 7 10:21:34 2026 - [info] Executing master ip online change script to disable write on the current master:
Sat Mar 7 10:21:34 2026 - [info] /etc/masterha/scripts/master_ip_online_change --command=stop --orig_master_host=172.25.254.10 --orig_master_ip=172.25.254.10 --orig_master_port=3306 --orig_master_user='root' --new_master_host=172.25.254.20 --new_master_ip=172.25.254.20 --new_master_port=3306 --new_master_user='root' --orig_master_ssh_user=root --new_master_ssh_user=root --orig_master_is_new_slave --orig_master_password=xxx --new_master_password=xxx
***************************************************************
Disabling the VIP - 172.25.254.100/24 on old master: 172.25.254.10
***************************************************************
Error: ipv4: Address not found.
Sat Mar 7 10:21:34 2026 - [info] ok.
Sat Mar 7 10:21:34 2026 - [info] Locking all tables on the orig master to reject updates from everybody (including root):
Sat Mar 7 10:21:34 2026 - [info] Executing FLUSH TABLES WITH READ LOCK..
Sat Mar 7 10:21:34 2026 - [info] ok.
Sat Mar 7 10:21:34 2026 - [info] Orig master binlog:pos is mysql-bin.000002:1968.
Sat Mar 7 10:21:34 2026 - [info] Waiting to execute all relay logs on 172.25.254.20(172.25.254.20:3306)..
Sat Mar 7 10:21:34 2026 - [info] master_pos_wait(mysql-bin.000002:1968) completed on 172.25.254.20(172.25.254.20:3306). Executed 0 events.
Sat Mar 7 10:21:34 2026 - [info] done.
Sat Mar 7 10:21:34 2026 - [info] Getting new master's binlog name and position..
Sat Mar 7 10:21:34 2026 - [info] mysql-bin.000002:2337
Sat Mar 7 10:21:34 2026 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='172.25.254.20', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='lee', MASTER_PASSWORD='xxx';
Sat Mar 7 10:21:34 2026 - [info] Executing master ip online change script to allow write on the new master:
Sat Mar 7 10:21:34 2026 - [info] /etc/masterha/scripts/master_ip_online_change --command=start --orig_master_host=172.25.254.10 --orig_master_ip=172.25.254.10 --orig_master_port=3306 --orig_master_user='root' --new_master_host=172.25.254.20 --new_master_ip=172.25.254.20 --new_master_port=3306 --new_master_user='root' --orig_master_ssh_user=root --new_master_ssh_user=root --orig_master_is_new_slave --orig_master_password=xxx --new_master_password=xxx
***************************************************************
Enabling the VIP - 172.25.254.100/24 on new master: 172.25.254.20
***************************************************************
Sat Mar 7 10:21:34 2026 - [info] ok.
Sat Mar 7 10:21:34 2026 - [info]
Sat Mar 7 10:21:34 2026 - [info] * Switching slaves in parallel..
Sat Mar 7 10:21:34 2026 - [info]
Sat Mar 7 10:21:34 2026 - [info] -- Slave switch on host 172.25.254.30(172.25.254.30:3306) started, pid: 1654
Sat Mar 7 10:21:34 2026 - [info]
Sat Mar 7 10:21:35 2026 - [info] Log messages from 172.25.254.30 ...
Sat Mar 7 10:21:35 2026 - [info]
Sat Mar 7 10:21:34 2026 - [info] Waiting to execute all relay logs on 172.25.254.30(172.25.254.30:3306)..
Sat Mar 7 10:21:34 2026 - [info] master_pos_wait(mysql-bin.000002:1968) completed on 172.25.254.30(172.25.254.30:3306). Executed 0 events.
Sat Mar 7 10:21:34 2026 - [info] done.
Sat Mar 7 10:21:34 2026 - [info] Resetting slave 172.25.254.30(172.25.254.30:3306) and starting replication from the new master 172.25.254.20(172.25.254.20:3306)..
Sat Mar 7 10:21:34 2026 - [info] Executed CHANGE MASTER.
Sat Mar 7 10:21:34 2026 - [info] Slave started.
Sat Mar 7 10:21:35 2026 - [info] End of log messages from 172.25.254.30 ...
Sat Mar 7 10:21:35 2026 - [info]
Sat Mar 7 10:21:35 2026 - [info] -- Slave switch on host 172.25.254.30(172.25.254.30:3306) succeeded.
Sat Mar 7 10:21:35 2026 - [info] Unlocking all tables on the orig master:
Sat Mar 7 10:21:35 2026 - [info] Executing UNLOCK TABLES..
Sat Mar 7 10:21:35 2026 - [info] ok.
Sat Mar 7 10:21:35 2026 - [info] Starting orig master as a new slave..
Sat Mar 7 10:21:35 2026 - [info] Resetting slave 172.25.254.10(172.25.254.10:3306) and starting replication from the new master 172.25.254.20(172.25.254.20:3306)..
Sat Mar 7 10:21:35 2026 - [info] Executed CHANGE MASTER.
Sat Mar 7 10:21:35 2026 - [info] Slave started.
Sat Mar 7 10:21:35 2026 - [info] All new slave servers switched successfully.
Sat Mar 7 10:21:35 2026 - [info]
Sat Mar 7 10:21:35 2026 - [info] * Phase 5: New master cleanup phase..
Sat Mar 7 10:21:35 2026 - [info]
Sat Mar 7 10:21:35 2026 - [info] 172.25.254.20: Resetting slave info succeeded.
Sat Mar 7 10:21:35 2026 - [info] Switching master to 172.25.254.20(172.25.254.20:3306) completed successfully.
#查看集群状态
[root@mysql-node1 ~]# mysql -uroot -plee -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.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node1-relay-bin.000002
Relay_Log_Pos: 742
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
[root@mysql-node3 ~]# mysql -uroot -plee -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.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 742
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
master故障切换
bash
[root@mha ~]# masterha_master_switch --master_state=dead --conf=/etc/masterha/app1.cnf --dead_master_host=172.25.254.10 --dead_master_port=3306 --new_master_host=172.25.254.20 --new_master_port=3306 --ignore_last_failover
--dead_master_ip=<dead_master_ip> is not set. Using 172.25.254.10.
Sat Mar 7 10:26:01 2026 - [warning] Global configuration file /etc/masterha_default.cnf not found. Skipping.
Sat Mar 7 10:26:01 2026 - [info] Reading application default configuration from /etc/masterha/app1.cnf..
Sat Mar 7 10:26:01 2026 - [info] Reading server configuration from /etc/masterha/app1.cnf..
Sat Mar 7 10:26:01 2026 - [info] MHA::MasterFailover version 0.58.
Sat Mar 7 10:26:01 2026 - [info] Starting master failover.
Sat Mar 7 10:26:01 2026 - [info]
Sat Mar 7 10:26:01 2026 - [info] * Phase 1: Configuration Check Phase..
Sat Mar 7 10:26:01 2026 - [info]
Sat Mar 7 10:26:02 2026 - [info] GTID failover mode = 1
Sat Mar 7 10:26:02 2026 - [info] Dead Servers:
Sat Mar 7 10:26:02 2026 - [info] 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:02 2026 - [info] Checking master reachability via MySQL(double check)...
Sat Mar 7 10:26:02 2026 - [info] ok.
Sat Mar 7 10:26:02 2026 - [info] Alive Servers:
Sat Mar 7 10:26:02 2026 - [info] 172.25.254.20(172.25.254.20:3306)
Sat Mar 7 10:26:02 2026 - [info] 172.25.254.30(172.25.254.30:3306)
Sat Mar 7 10:26:02 2026 - [info] Alive Slaves:
Sat Mar 7 10:26:02 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:02 2026 - [info] GTID ON
Sat Mar 7 10:26:02 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:02 2026 - [info] Primary candidate for the new Master (candidate_master is set)
Sat Mar 7 10:26:02 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:02 2026 - [info] GTID ON
Sat Mar 7 10:26:02 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:02 2026 - [info] Not candidate for the new Master (no_master is set)
Master 172.25.254.10(172.25.254.10:3306) is dead. Proceed? (yes/NO): yes #输入内容
Sat Mar 7 10:26:08 2026 - [info] Starting GTID based failover.
Sat Mar 7 10:26:08 2026 - [info]
Sat Mar 7 10:26:08 2026 - [info] ** Phase 1: Configuration Check Phase completed.
Sat Mar 7 10:26:08 2026 - [info]
Sat Mar 7 10:26:08 2026 - [info] * Phase 2: Dead Master Shutdown Phase..
Sat Mar 7 10:26:08 2026 - [info]
Sat Mar 7 10:26:08 2026 - [info] HealthCheck: SSH to 172.25.254.10 is reachable.
Sat Mar 7 10:26:09 2026 - [info] Forcing shutdown so that applications never connect to the current master..
Sat Mar 7 10:26:09 2026 - [info] Executing master IP deactivation script:
Sat Mar 7 10:26:09 2026 - [info] /etc/masterha/scripts/master_ip_failover --orig_master_host=172.25.254.10 --orig_master_ip=172.25.254.10 --orig_master_port=3306 --command=stopssh --ssh_user=root
IN SCRIPT TEST====/sbin/ip addr del 172.25.254.100/24 dev eth0==/sbin/ip addr add 172.25.254.100/24 dev eth0===
Disabling the VIP on old master: 172.25.254.10
Sat Mar 7 10:26:09 2026 - [info] done.
Sat Mar 7 10:26:09 2026 - [warning] shutdown_script is not set. Skipping explicit shutting down of the dead master.
Sat Mar 7 10:26:09 2026 - [info] * Phase 2: Dead Master Shutdown Phase completed.
Sat Mar 7 10:26:09 2026 - [info]
Sat Mar 7 10:26:09 2026 - [info] * Phase 3: Master Recovery Phase..
Sat Mar 7 10:26:09 2026 - [info]
Sat Mar 7 10:26:09 2026 - [info] * Phase 3.1: Getting Latest Slaves Phase..
Sat Mar 7 10:26:09 2026 - [info]
Sat Mar 7 10:26:09 2026 - [info] The latest binary log file/position on all slaves is mysql-bin.000002:2295
Sat Mar 7 10:26:09 2026 - [info] Latest slaves (Slaves that received relay log files to the latest):
Sat Mar 7 10:26:09 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:09 2026 - [info] GTID ON
Sat Mar 7 10:26:09 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:09 2026 - [info] Primary candidate for the new Master (candidate_master is set)
Sat Mar 7 10:26:09 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:09 2026 - [info] GTID ON
Sat Mar 7 10:26:09 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:09 2026 - [info] Not candidate for the new Master (no_master is set)
Sat Mar 7 10:26:09 2026 - [info] The oldest binary log file/position on all slaves is mysql-bin.000002:2295
Sat Mar 7 10:26:09 2026 - [info] Oldest slaves:
Sat Mar 7 10:26:09 2026 - [info] 172.25.254.20(172.25.254.20:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:09 2026 - [info] GTID ON
Sat Mar 7 10:26:09 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:09 2026 - [info] Primary candidate for the new Master (candidate_master is set)
Sat Mar 7 10:26:09 2026 - [info] 172.25.254.30(172.25.254.30:3306) Version=8.3.0 (oldest major version between slaves) log-bin:enabled
Sat Mar 7 10:26:09 2026 - [info] GTID ON
Sat Mar 7 10:26:09 2026 - [info] Replicating from 172.25.254.10(172.25.254.10:3306)
Sat Mar 7 10:26:09 2026 - [info] Not candidate for the new Master (no_master is set)
Sat Mar 7 10:26:09 2026 - [info]
Sat Mar 7 10:26:09 2026 - [info] * Phase 3.3: Determining New Master Phase..
Sat Mar 7 10:26:09 2026 - [info]
Sat Mar 7 10:26:09 2026 - [info] 172.25.254.20 can be new master.
Sat Mar 7 10:26:09 2026 - [info] New master is 172.25.254.20(172.25.254.20:3306)
Sat Mar 7 10:26:09 2026 - [info] Starting master failover..
Sat Mar 7 10:26:09 2026 - [info]
From:
172.25.254.10(172.25.254.10:3306) (current master)
+--172.25.254.20(172.25.254.20:3306)
+--172.25.254.30(172.25.254.30:3306)
To:
172.25.254.20(172.25.254.20:3306) (new master)
+--172.25.254.30(172.25.254.30:3306)
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 10:26:13 2026 - [info] New master decided manually is 172.25.254.20(172.25.254.20:3306)
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] * Phase 3.3: New Master Recovery Phase..
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] Waiting all logs to be applied..
Sat Mar 7 10:26:13 2026 - [info] done.
Sat Mar 7 10:26:13 2026 - [info] Getting new master's binlog name and position..
Sat Mar 7 10:26:13 2026 - [info] mysql-bin.000002:2337
Sat Mar 7 10:26:13 2026 - [info] All other slaves should start replication from here. Statement should be: CHANGE MASTER TO MASTER_HOST='172.25.254.20', MASTER_PORT=3306, MASTER_AUTO_POSITION=1, MASTER_USER='lee', MASTER_PASSWORD='xxx';
Sat Mar 7 10:26:13 2026 - [info] Master Recovery succeeded. File:Pos:Exec_Gtid_Set: mysql-bin.000002, 2337, 1b73d49c-19c8-11f1-a11b-000c29e84b64:1,
b9652041-19c7-11f1-a4c3-000c29f4a60c:1-7
Sat Mar 7 10:26:13 2026 - [info] Executing master IP activate script:
Sat Mar 7 10:26:13 2026 - [info] /etc/masterha/scripts/master_ip_failover --command=start --ssh_user=root --orig_master_host=172.25.254.10 --orig_master_ip=172.25.254.10 --orig_master_port=3306 --new_master_host=172.25.254.20 --new_master_ip=172.25.254.20 --new_master_port=3306 --new_master_user='root' --new_master_password=xxx
Unknown option: new_master_user
Unknown option: new_master_password
IN SCRIPT TEST====/sbin/ip addr del 172.25.254.100/24 dev eth0==/sbin/ip addr add 172.25.254.100/24 dev eth0===
Enabling the VIP - 172.25.254.100/24 on the new master - 172.25.254.20
Sat Mar 7 10:26:13 2026 - [info] OK.
Sat Mar 7 10:26:13 2026 - [info] Setting read_only=0 on 172.25.254.20(172.25.254.20:3306)..
Sat Mar 7 10:26:13 2026 - [info] ok.
Sat Mar 7 10:26:13 2026 - [info] ** Finished master recovery successfully.
Sat Mar 7 10:26:13 2026 - [info] * Phase 3: Master Recovery Phase completed.
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] * Phase 4: Slaves Recovery Phase..
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] * Phase 4.1: Starting Slaves in parallel..
Sat Mar 7 10:26:13 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] -- Slave recovery on host 172.25.254.30(172.25.254.30:3306) started, pid: 1681. Check tmp log /etc/masterha/172.25.254.30_3306_20260307102601.log if it takes time..
Sat Mar 7 10:26:14 2026 - [info]
Sat Mar 7 10:26:14 2026 - [info] Log messages from 172.25.254.30 ...
Sat Mar 7 10:26:14 2026 - [info]
Sat Mar 7 10:26:13 2026 - [info] Resetting slave 172.25.254.30(172.25.254.30:3306) and starting replication from the new master 172.25.254.20(172.25.254.20:3306)..
Sat Mar 7 10:26:13 2026 - [info] Executed CHANGE MASTER.
Sat Mar 7 10:26:13 2026 - [info] Slave started.
Sat Mar 7 10:26:13 2026 - [error][/usr/share/perl5/vendor_perl/MHA/Server.pm, ln974] gtid_wait(1b73d49c-19c8-11f1-a11b-000c29e84b64:1,
b9652041-19c7-11f1-a4c3-000c29f4a60c:1-7) returned NULL on 172.25.254.30(172.25.254.30:3306). Maybe SQL thread was aborted?
Sat Mar 7 10:26:14 2026 - [info] End of log messages from 172.25.254.30.
Sat Mar 7 10:26:14 2026 - [error][/usr/share/perl5/vendor_perl/MHA/MasterFailover.pm, ln2045] Master failover to 172.25.254.20(172.25.254.20:3306) done, but recovery on slave partially failed.
Sat Mar 7 10:26:14 2026 - [info]
----- Failover Report -----
app1: MySQL Master failover 172.25.254.10(172.25.254.10:3306) to 172.25.254.20(172.25.254.20:3306)
Master 172.25.254.10(172.25.254.10:3306) is down!
Check MHA Manager logs at mha for details.
Started manual(interactive) failover.
Invalidated master IP address on 172.25.254.10(172.25.254.10:3306)
Selected 172.25.254.20(172.25.254.20:3306) as a new master.
172.25.254.20(172.25.254.20:3306): OK: Applying all logs succeeded.
172.25.254.20(172.25.254.20:3306): OK: Activated master IP address.
172.25.254.30(172.25.254.30:3306): ERROR: Failed on waiting gtid exec set on master.
Master failover to 172.25.254.20(172.25.254.20:3306) done, but recovery on slave partially failed.
#查看切换信息
[root@mysql-node3 ~]# mysql -uroot -plee -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.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node3-relay-bin.000002
Relay_Log_Pos: 422
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
#故障恢复
#当出现故障切换后,mha主机中会出现切换锁文件,当文件存在后不能再次执行切换
[root@mha ~]# ls /etc/masterha/
app1.cnf app1.failover.complete mha.log scripts
|
#锁文件
[root@mha ~]# rm -fr /etc/masterha/app1.failover.complete
[root@mysql-node2 ~]# mysql -uroot -plee -e "reset slave;"
[root@mysql-node1 ~]# /etc/init.d/mysqld start
Starting MySQL. SUCCESS!
mysql -uroot -plee -e "CHANGE MASTER TO MASTER_HOST='172.25.254.20', MASTER_USER='lee', MASTER_PASSWORD='lee', MASTER_AUTO_POSITION=1;"
[root@mysql-node1 ~]# mysql -uroot -plee -e "start slave;"
[root@mysql-node1 ~]# mysql -uroot -plee -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.20
Master_User: lee
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 2337
Relay_Log_File: mysql-node1-relay-bin.000002
Relay_Log_Pos: 422
Relay_Master_Log_File: mysql-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
注意:
如果之前的环境中开启了半同步模式,那么在做此处实验时会报错
bash
Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction 'd77b3abd-92cb-11f1-abed-000c29f195bc:1' at source log mysql-binlog.000003, end_log_pos 1566. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any.
解决方案:
bash
mysql> stop replica;
mysql> SET GTID_NEXT='d77b3abd-92cb-11f1-abed-000c29f195bc:1';
mysql> BEGIN;COMMIT;
mysql> SET GTID_NEXT='AUTOMATIC';
mysql> start replica;
自动切换
bash
#为了方便观察建议开启两个shell
[root@mha ~]# > /etc/masterha/*.log
[root@mha ~]# watch -n 1 cat /etc/masterha/mha.log
#开启自动切换功能
[root@mha ~]# masterha_manager --conf=/etc/masterha/app1.cnf &
[root@mha ~]# jobs
[1]+ 运行中 masterha_manager --conf=/etc/masterha/app1.cnf &
#模拟故障
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
3.ip功能及vip的启动切换
bash
[root@mha ~]# unzip MHA-7.zip
[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@mysql-node1 ~]# ip a a 172.25.254.100/24 dev eth0
#测试:
[root@mha ~]# masterha_manager --conf=/etc/masterha/app1.cnf &
[root@mha ~]# jobs
[1]+ 运行中 masterha_manager --conf=/etc/masterha/app1.cnf &
#关闭mysql master
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
[root@mysql-node2 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:e8:4b:64 brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.20/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet 172.25.254.100/24 scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 fe80::f8be:d443:72d7:d336/64 scope link noprefixroute
valid_lft forever preferred_lft forever
5.MySQL集群实战------>MySQL组复制
MySQL组复制(MySQL Group Replication,简称MGR)是MySQL官方在5.7.17版本中正式推出的高可用与高扩展解决方案 。它基于Paxos分布式共识协议 实现,将一组MySQL实例组织成一个复制组。组内每个成员都拥有数据的完整副本(Shared-Nothing架构),通过组内通信和共识机制,实现数据的强一致性 和自动故障转移
就像是给MySQL集群装上了一套 "民主投票系统" 。以前的主从复制,是"主库"说了算,从库跟着学。而MGR让一群MySQL服务器组成一个"小组",任何重要操作(比如提交一个事务)都需要组内超过半数(多数派)的成员投票同意才能执行。这就好比一个决策需要董事会多数票通过,极大地保证了数据的可靠性和一致性。
MGR作为MySQL的一个插件,其架构主要分为三层:
-
组通信层(Group Communication System, GCS) :负责节点间的消息传递、成员管理和故障检测。其核心是一个基于Paxos协议的XCom引擎。
-
复制协议模块 :处理冲突检测,并确保事务在组内以全局顺序进行传输和应用。
-
API与组件层:提供与MySQL服务器交互的接口,负责捕获(Capture)、应用(Apply)和恢复(Recovery)事务
MGR的核心工作原理可以概括为"先商量,后干活":
-
事务发起:你在某个节点(成员)上执行了一个写操作(事务)。
-
组内广播:这个节点不会自己偷偷提交,而是把事务内容"广播"给组里的所有其他成员。
-
投票表决(关键) :所有成员收到事务后,会运行一个"冲突检测"程序。大家会检查这个事务是否跟本地正在执行的其他事务有冲突(比如是否修改了同一行数据)。只有当超过半数的成员都"投票"通过,认为没有冲突时,这个事务才算被"认证"通过。
-
统一执行:一旦"认证"通过,所有成员会在同一个"全局顺序"上执行这个事务,保证大家的数据最终是完全一样的。
MGR支持两种部署模式,以适应不同场景
| 模式 | 大白话 | 书面语 |
|---|---|---|
| 单主模式 (Single-Primary) | 组里只有一个"老大"(主节点)能写数据,其他成员都只能读。如果老大挂了,剩下的人会通过投票自动选出一个新老大 。这是最常用、最推荐的模式。 | 组内只有一个节点可读写(Primary),其余节点只读(Secondary)。主节点故障时,剩余节点通过Paxos协议自动选举新主,切换过程对应用透明。 |
| 多主模式 (Multi-Primary) | 组里所有成员都能写。适合写入压力非常大的场景,但需要应用处理可能出现的写冲突(比如两个节点同时改同一条数据)。 | 所有节点均可同时读写。通过行级冲突检测来保证数据最终一致,但存在全局锁竞争 和大事务阻塞集群的风险,实际生产环境使用较少 |
配置
利用ansible还原所有节点
bash
#利用ansible还原所有节点
[root@mha ~]# cat > /etc/yum.repos.d/epel.repo <<EOF
> [epel]
> name = epel
> baseurl = https://mirrors.aliyun.com/epel-archive/9.6/Everything/x86_64/
> gpgcheck = 0
> EOF
[root@mha ~]# dnf install ansible -y
[root@mha ~]# 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 lee | passwd --stdin devops
[root@mha ~]# su - devops
[devops@mha ~]$ mkdir ansible
[devops@mha ansible]$ cat >ansible.cfg <<EOF
[defaults]
inventory=./inventory
remote_user=root
host_key_checking=false
[privilege_escalation]
become=False
EOF
[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
手动还原方式
bash
#所有节点初始化数据
[root@mysql-node1 ~]# /etc/init.d/mysqld stop
[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|20|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"
EOF
[root@mysql-node1 ~]# mysqld --user=mysql --initialize
部署组复制
bash
#设置所有mysql节点的解析
[root@mysql-node1 ~]# cat > /etc/hosts <<EOF
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
EOF
[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
#配置组复制-在首台主机中
[root@mysql-node1 ~]# mysql -uroot -p'lsyVh+etR1ht'
mysql> alter user root@localhost identified by 'lee';
Query OK, 0 rows affected (0.04 sec)
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'lee';
Query OK, 0 rows affected (0.00 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> 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='lee' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.01 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='lee';
Query OK, 0 rows affected (1.10 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;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | ac3d6eaf-1a0a-11f1-9efa-000c29f4a60c | mysql-node1 | 3306 | ONLINE | PRIMARY | 8.3.0 | XCom |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
1 row in set (0.00 sec)
#配置组复制在其余主机中
[root@mysql-node2 ~]# /etc/init.d/mysqld start
[root@mysql-node2 ~]# mysql -uroot -p'XkP<Uaa:9so5'
mysql> alter user root@localhost identified by 'lee';
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 'lee';
Query OK, 0 rows affected (0.00 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='lee' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='lee';
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.04 sec)
mysql> START GROUP_REPLICATION USER='rpl_user', PASSWORD='lee';
Query OK, 0 rows affected (7.94 sec)
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE | MEMBER_ROLE | MEMBER_VERSION | MEMBER_COMMUNICATION_STACK |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
| group_replication_applier | ac3d6eaf-1a0a-11f1-9efa-000c29f4a60c | mysql-node1 | 3306 | ONLINE | PRIMARY | 8.3.0 | XCom |
| group_replication_applier | e0b37b20-1a0b-11f1-a62c-000c29e84b64 | mysql-node2 | 3306 | ONLINE | PRIMARY | 8.3.0 | XCom |
+---------------------------+--------------------------------------+-------------+-------------+--------------+-------------+----------------+----------------------------+
2 rows in set (0.00 sec)
#看到主机online表示成功
三台主机部署储成功后的效果

测试
bash
#测试所有节点是否可以执行读写并数据是否同步
#node1中
mysql> create database timinglee;
Query OK, 1 row affected (0.00 sec)
mysql> create table timinglee.userlist (
-> username VARCHAR(10) PRIMARY KEY NOT NULL,
-> password VARCHAR(50) NOT NULL
-> );
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO timinglee.userlist VALUES ('user1','111');
Query OK, 1 row affected (0.01 sec)
#在node2中查看并插入新的数据
mysql> select * from timinglee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
+----------+----------+
1 row in set (0.00 sec)
mysql> insert into timinglee.userlist values ('user2','222');
Query OK, 1 row affected (0.01 sec)
mysql> select * from timinglee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
+----------+----------+
2 rows in set (0.01 sec)
#在node3中查看并插入数据
mysql> select * from timinglee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
+----------+----------+
2 rows in set (0.00 sec)
mysql> insert into timinglee.userlist values ('user3','333');
Query OK, 1 row affected (0.01 sec)
mysql> select * from timinglee.userlist;
+----------+----------+
| username | password |
+----------+----------+
| user1 | 111 |
| user2 | 222 |
| user3 | 333 |
+----------+----------+
3 rows in set (0.00 sec)
mysql>
#在node1和2中也可以看到以上数据
6.MySQL集群实战------>MySQLrouter
MySQL Router是MySQL官方提供的一款轻量级中间件 。它位于应用程序与后端MySQL服务器之间,充当一个透明的代理层 。其核心价值在于为应用程序提供一个稳定、统一的数据库访问入口 ,并在此入口处实现高可用(HA)、负载均衡(LB)和读写分离等关键能力。应用程序不再感知后端集群复杂的拓扑变化,从而极大地简化了开发和运维工作。
就像是你数据库集群的 "智能前台" 。以前你的应用(App)要连接数据库,得直接去找具体的数据库服务器IP,一旦主库挂了或者集群机器换了,应用就得改配置重启,非常麻烦。现在有了Router这个"前台",应用只需要知道Router的地址就行。所有对数据库的请求都先交给它,由它来决定:"这个写请求,送到主库去"、"这个读请求,找个空闲的从库处理"、"主库宕机了?别担心,我已经自动切到新主库了"。整个过程对应用完全透明,应用代码一行都不用改。
Router就像一个全能的"交通警察",其核心功能主要体现在以下几个方面:
-
🎯 透明路由(Transparent Routing):应用程序将Router视为一个普通的MySQL服务器进行连接。Router接收到请求后,会根据预设策略,将连接路由到后端的某个MySQL实例上。
-
🔄 读写分离(Read/Write Splitting):这是Router最核心的功能之一。它能智能识别SQL语句的类型:
-
写操作 (如
INSERT,UPDATE,DELETE等)会被自动路由到主库(Primary)。 -
读操作 (主要是
SELECT查询)则会被分发到一个或多个从库(Secondary) 上,实现负载均衡。 -
从MySQL 8.2开始,Router支持更智能的"自动读写分离",甚至能在同一个数据库连接中,根据事务状态自动切换路由。
-
-
🚑 高可用与自动故障转移(High Availability & Failover):Router会持续监控后端MySQL服务器的健康状态。一旦检测到主库发生故障:
-
Router会立即将其从可用列表中移除。
-
如果后端是InnoDB Cluster,集群会自动选举出新的主库。
-
Router会自动 感知这一变化,并将后续的写请求路由到新的主库上。整个过程对应用完全透明,通常在几秒内即可完成。
-
-
⚖️ 负载均衡(Load Balancing) :对于路由到从库的读请求,Router支持多种负载均衡策略,如轮询(Round-Robin),将读流量均匀分散到各个从库上,避免单个从库压力过大
Router的工作原理可以用"缓存+监听"来概括:
-
启动时"抄名单" :Router启动时,会连接到你指定的MySQL集群(比如InnoDB Cluster),把整个集群的拓扑信息(谁是主、谁是从、谁活着、谁死了)都"抄"一份,存在自己的元数据缓存(Metadata Cache) 里。
-
运行时"看路标":当应用发起连接请求时,Router会根据请求类型(读/写)和自己的路由策略(如轮询),从缓存中挑选一个最合适的后端服务器,然后建立起应用和这个服务器之间的"通道"。
-
持续"监听广播" :Router会持续监听集群的状态。一旦集群发生变化(比如节点宕机、主从切换),它会立刻收到"广播",并自动更新自己的元数据缓存。这样,下一次有请求过来时,Router就能用最新的"名单"进行路由了。
(1)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
(2)安装mysqlrouter
bash
[root@mysqlrouter ~]# dnf install mysql-router-community-8.4.7-1.el9.x86_64.rpm -y
(3)mysqlrouter配置文件
bash
[root@mysqlrouter ~]# rpm -qc mysql-router-community
/etc/logrotate.d/mysqlrouter #日志轮询及日志截断策略
/etc/mysqlrouter/mysqlrouter.conf #主配置文件
[root@mysqlrouter ~]# systemctl status mysqlrouter.service #启动脚本
(4)配置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
(5)测试
bash
#在mysql节点的任意主机中添加root远程登录
[root@mysql-node1 ~]# mysql -uroot -plee
mysql> CREATE USER root@'%' identified by 'lee';
Query OK, 0 rows affected (0.00 sec)
mysql> GRANT ALL ON *.* TO root@'%';
Query OK, 0 rows affected (0.00 sec)
mysql> quit
Bye
[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
#查看调度效果
[root@mysql-node10 & 20 & 30 ~]# watch -n1 lsof -i :3306
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mysqld 9879 mysql 22u IPv6 56697 0t0 TCP *:mysql (LISTEN)
#测试效果
[root@mysql-node1 ~]# mysql -uroot -plee -h172.25.254.40 -P7002
(6)组复制算法
| 策略 | 说明 | 典型使用场景 |
|---|---|---|
| first‑available | 优先连接列表里第一个可用节点;第一个挂了,自动切第二个,节点恢复后切回第一个。故障节点恢复后会自动切回去 | MGR/InnoDB Cluster 读写端口 (6446),单主模式,业务写请求,默认 mode=read‑write 底层就是该策略 |
| next‑available | 取列表第一个可用节点;故障后永不自动切回原节点,只往后找,就算原节点恢复也不会回去 | 静态后端列表,不想故障自动回迁的场景 |
| round‑robin | 轮询,新连接依次分配给每一台可用后端,连接尽量均匀分摊 | MGR 只读端口 (6447),读请求负载均衡,mode=read‑only 默认底层策略 |
| round‑robin‑with‑fallback | 优先轮询从库 (secondary);所有从库全部不可用,才降级轮询主库 (primary) | 读写分离,读压力尽量走从机,从机全部宕机才把读流量打到主库Oracle |