一、环境准备
主机名 | ip | 操作系统 | 备注 |
---|---|---|---|
node01 | 192.168.48.91 | CentOS Linux 7 (Core) | mysql主库 |
node01 | 192.168.48.92 | CentOS Linux 7 (Core) | mysql主库 |
192.168.48.90 | 漂移IP(VIP) |
centos7镜像下载地址:
https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2207-02.iso
二、安装mysql8
node01&node02
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
yum makecache
yum update
systemctl disable --now firewalld
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/sysconfig/selinux
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
sed -i '3 s/^/# /' /etc/chrony.conf
sed -i '4 a server ntp.aliyun.com iburst' /etc/chrony.conf
systemctl restart chronyd.service
systemctl enable chronyd.service
chronyc sources
wget http://dev.mysql.com/get/mysql80-community-release-el7-8.noarch.rpm
yum localinstall -y mysql80-community-release-el7-8.noarch.rpm
yum repolist enabled | grep mysql
yum -y install mysql-community-server --nogpgcheck
rpm -qa |grep mysql
systemctl start mysqld
systemctl enable mysqld
systemctl daemon-reload
#查看mysql密码
cat /var/log/mysqld.log | grep password
#2025-08-29T05:53:37.423668Z 6 [Note] [MY-010454] [Server] A temporary password is generated for #root@localhost: Oeblh;:dK1ba
#使用密码登录
mysql -uroot -p 'Oeblh;:dK1ba'
#修改密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Admin123.';
#创建远程连接用户
create user 'root'@'%' identified with mysql_native_password by 'Admin123.';
grant all privileges on *.* to 'root'@'%' with grant option;
flush privileges;
三、mysql主主复制
流程图:
flowchart TD
A[开始配置MySQL从库] --> B[修改从库配置文件my.cnf]
B --> C[重启从库MySQL服务]
C --> D[创建主库数据快照并导入从库]
D --> E[在从库上配置主库连接信息]
E --> F[启动从库复制进程]
F --> G[检查从库复制状态]
G --> H{Slave_IO_Running和<br>Slave_SQL_Running是否均为Yes?}
H -->|是| I[主从复制建立成功]
H -->|否| J[根据错误信息排查问题]
J --> E

1. 修改配置文件
1.1. node01
这里开启了GTID。
vim /etc/my.cnf
[mysqld]
# 数据文件存储目录。MySQL所有的数据库数据(表、索引等)都存放在这个路径下。
datadir=/var/lib/mysql
# MySQL服务器监听的Unix套接字文件路径。本地客户端可以通过这个socket文件连接数据库,速度比TCP/IP更快。
socket=/var/lib/mysql/mysql.sock
# MySQL错误日志文件的存放路径。启动失败、运行错误等信息都会记录在这里,是排查问题的重要依据。
log-error=/var/log/mysqld.log
# 存储MySQL服务进程ID(PID)的文件路径。系统和管理工具通过读取这个文件来获取MySQL的进程号。
pid-file=/var/run/mysqld/mysqld.pid
# 服务节点ID,在复制拓扑(主从/主主)中每个实例必须具有唯一ID(1-2^32-1)。
# 主从复制中,主库和从库的server-id必须不同。
server-id=1
# 开启二进制日志(binlog)并设置二进制日志文件的基本名。
# binlog记录了所有更改数据的SQL语句,用于主从复制和数据恢复。
log-bin=master-bin
# 【谨慎使用】指定需要记录二进制日志的数据库。只有在此列表中数据库的更改才会被写入binlog。
# 基于"当前USE的数据库"进行过滤,有风险(如:在db1中更新db2的表将不会被记录)。
# 建议使用反向过滤(binlog-ignore-db)或在从库过滤,而非在此正向过滤。
binlog-do-db=your_database_name
# 设置中继日志的文件名。中继日志存在于从库,用于存储从主库binlog读取到的数据更改事件。
relay-log=mysql-relay-bin
# 【推荐方式】指定不记录二进制日志的数据库(反向过滤,更安全)。
# 通常忽略MySQL系统自带的数据库,避免不必要的复制。
binlog_ignore_db=sys # 忽略sys系统库
binlog_ignore_db=mysql # 忽略mysql系统库(存储用户权限等信息)
binlog_ignore_db=information_schema # 忽略information_schema虚拟库(存储元数据)
binlog_ignore_db=performance_schema # 忽略performance_schema虚拟库(存储性能指标)
# --- 自增字段全局配置(在多主复制架构中用于避免自增ID冲突)---
# 自增字段每次增长的步长。在双主模式下通常设置为节点的总数。
auto_increment_increment=2
# 自增字段的起始偏移量。每个实例应设置不同的偏移量(如1和2),确保ID不会冲突。
auto_increment_offset=1
# --- 从库复制过滤规则(通常配置在从库的my.cnf中,主库配置无效)---
# 指定从库需要复制的数据库。与binlog-do-db类似,有基于默认数据库过滤的风险。
# replicate_do_db=test
# 指定从库需要忽略的数据库。
# replicate_ignore_db=mysql
# --- 字符集与排序规则配置 ---
# 设置MySQL服务器的默认字符集为utf8mb4,支持存储所有的UTF-8字符,包括表情符号(emoji)。
character-set-server=utf8mb4
# 设置服务器默认的排序规则(collation)。utf8mb4_unicode_ci基于Unicode标准排序,精度高。
collation-server=utf8mb4_unicode_ci
# --- 事务隔离级别 ---
# 设置默认的事务隔离级别为READ-COMMITTED(读已提交)。
# 此级别可以避免脏读,但可能出现不可重复读和幻读。许多复制场景推荐使用此级别。
transaction-isolation=READ-COMMITTED
# --- GTID(全局事务标识符)配置 ---
# 开启GTID模式。GTID为每个提交的事务生成一个全局唯一的ID,简化了复制的维护和故障恢复。
gtid-mode=on
# 强制GTID一致性,确保所有事务都可以以事务安全的方式被记录和复制。
enforce-gtid-consistency=true
1.2. node02
vim /etc/my.cnf
[mysqld]
# 数据文件存储目录。MySQL所有的数据库数据(表、索引等)都存放在这个路径下。
datadir=/var/lib/mysql
# MySQL服务器监听的Unix套接字文件路径。本地客户端可以通过这个socket文件连接数据库,速度比TCP/IP更快。
socket=/var/lib/mysql/mysql.sock
# MySQL错误日志文件的存放路径。启动失败、运行错误等信息都会记录在这里,是排查问题的重要依据。
log-error=/var/log/mysqld.log
# 存储MySQL服务进程ID(PID)的文件路径。系统和管理工具通过读取这个文件来获取MySQL的进程号。
pid-file=/var/run/mysqld/mysqld.pid
# 服务节点ID,在复制拓扑(主从/主主)中每个实例必须具有唯一ID(1-2^32-1)。
# 主从复制中,主库和从库的server-id必须不同。
server-id=2
# 开启二进制日志(binlog)并设置二进制日志文件的基本名。
# binlog记录了所有更改数据的SQL语句,用于主从复制和数据恢复。
log-bin=master-bin
# 【谨慎使用】指定需要记录二进制日志的数据库。只有在此列表中数据库的更改才会被写入binlog。
# 基于"当前USE的数据库"进行过滤,有风险(如:在db1中更新db2的表将不会被记录)。
# 建议使用反向过滤(binlog-ignore-db)或在从库过滤,而非在此正向过滤。
binlog-do-db=your_database_name
# 设置中继日志的文件名。中继日志存在于从库,用于存储从主库binlog读取到的数据更改事件。
relay-log=mysql-relay-bin
# 【推荐方式】指定不记录二进制日志的数据库(反向过滤,更安全)。
# 通常忽略MySQL系统自带的数据库,避免不必要的复制。
binlog_ignore_db=sys # 忽略sys系统库
binlog_ignore_db=mysql # 忽略mysql系统库(存储用户权限等信息)
binlog_ignore_db=information_schema # 忽略information_schema虚拟库(存储元数据)
binlog_ignore_db=performance_schema # 忽略performance_schema虚拟库(存储性能指标)
# --- 自增字段全局配置(在多主复制架构中用于避免自增ID冲突)---
# 自增字段每次增长的步长。在双主模式下通常设置为节点的总数。
auto_increment_increment=2
# 自增字段的起始偏移量。每个实例应设置不同的偏移量(如1和2),确保ID不会冲突。
auto_increment_offset=2
# --- 从库复制过滤规则(通常配置在从库的my.cnf中,主库配置无效)---
# 指定从库需要复制的数据库。与binlog-do-db类似,有基于默认数据库过滤的风险。
# replicate_do_db=test
# 指定从库需要忽略的数据库。
# replicate_ignore_db=mysql
# --- 字符集与排序规则配置 ---
# 设置MySQL服务器的默认字符集为utf8mb4,支持存储所有的UTF-8字符,包括表情符号(emoji)。
character-set-server=utf8mb4
# 设置服务器默认的排序规则(collation)。utf8mb4_unicode_ci基于Unicode标准排序,精度高。
collation-server=utf8mb4_unicode_ci
# --- 事务隔离级别 ---
# 设置默认的事务隔离级别为READ-COMMITTED(读已提交)。
# 此级别可以避免脏读,但可能出现不可重复读和幻读。许多复制场景推荐使用此级别。
transaction-isolation=READ-COMMITTED
# --- GTID(全局事务标识符)配置 ---
# 开启GTID模式。GTID为每个提交的事务生成一个全局唯一的ID,简化了复制的维护和故障恢复。
gtid-mode=on
# 强制GTID一致性,确保所有事务都可以以事务安全的方式被记录和复制。
enforce-gtid-consistency=true
2. 重启MySQL服务
node01&node02
sudo systemctl restart mysql
3. 创建复制用户
在两台服务器上创建一个用于复制的MySQL用户,并授予必要的权限。
node01
CREATE USER 'replication'@'192.168.48.92' IDENTIFIED WITH mysql_native_password BY 'Admin123.';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'192.168.48.92';
FLUSH PRIVILEGES;
CHANGE MASTER TO
MASTER_HOST='192.168.48.92',
MASTER_USER='replication',
MASTER_PASSWORD='Admin123.',
MASTER_AUTO_POSITION=1;
node02
CREATE USER 'replication'@'192.168.48.91' IDENTIFIED WITH mysql_native_password BY 'Admin123.';
GRANT REPLICATION SLAVE ON *.* TO 'replication'@'192.168.48.91';
FLUSH PRIVILEGES;
CHANGE MASTER TO
MASTER_HOST='192.168.48.91',
MASTER_USER='replication',
MASTER_PASSWORD='Admin123.',
MASTER_AUTO_POSITION=1;
4. 开启复制
node01&node02
#开启复制
START SLAVE;
#检查复制状态
SHOW SLAVE STATUS \G
#两个节点以下参数均为yes说明复制正常。
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
重点关注以下字段:
-
Slave_IO_Running
: Yes (表示I/O线程正常运行,能从主库读取binlog) -
Slave_SQL_Running
: Yes (表示SQL线程正常运行,能重放中继日志) -
Seconds_Behind_Master
: 0 (表示主从延迟为0秒。如果值不为0,说明存在延迟;如果为NULL,则需检查错误)18 -
Last_IO_Error
,Last_SQL_Error
: 如果复制进程异常,这里会显示错误信息
5. 验证
node01
CREATE DATABASE IF NOT EXISTS your_database_name;
USE your_database_name;
CREATE TABLE node01 (
id INT AUTO_INCREMENT PRIMARY KEY,
hostname VARCHAR(100) NOT NULL,
ip_address VARCHAR(15) NOT NULL,
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
description TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO node02 (hostname, ip_address, description)
VALUES ('master-node', '192.168.48.92', '这是主库节点01的测试数据,用于验证主从复制');
node02
USE your_database_name;
SELECT * FROM node01;
成功输出
mysql> SELECT * FROM node01;
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
| id | hostname | ip_address | status | created_at | updated_at | description |
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
| 1 | master-node | 192.168.48.92 | active | 2025-08-29 20:00:16 | 2025-08-29 20:00:16 | 这是主库节点01的测试数据,用于验证主从复制 |
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
1 row in set (0.00 sec)
node02
CREATE TABLE node02 (
id INT AUTO_INCREMENT PRIMARY KEY,
hostname VARCHAR(100) NOT NULL,
ip_address VARCHAR(15) NOT NULL,
status VARCHAR(20) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
description TEXT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO node02 (hostname, ip_address, description)
VALUES ('master-node', '192.168.48.91', '这是主库节点02的测试数据,用于验证主从复制');
node01
SELECT * FROM node02;
成功输出
mysql> SELECT * FROM node02;
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
| id | hostname | ip_address | status | created_at | updated_at | description |
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
| 2 | master-node | 192.168.48.91 | active | 2025-08-29 20:03:52 | 2025-08-29 20:03:52 | 这是主库节点02的测试数据,用于验证主从复制 |
+----+-------------+---------------+--------+---------------------+---------------------+----------------------------------------------------------------+
1 row in set (0.00 sec)
到此,主主复制完成
四、配置keepalived
1. 下载keepalived
node01&node02
yum install -y keepalived
2. 编写心跳检测脚本
node01&node02
cat > /etc/keepalived/mysql_check.sh << 'EOF'
#!/bin/bash
C=`ps -C mysqld --no-header | wc -l`
if [ $C -eq 0 ];then
exit 1
fi
exit 0
EOF
3. 修改配置文件
node01
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
vrrp_mcast_group4 224.0.0.18
}
vrrp_script check_mysql {
script "/etc/keepalived/mysql_check.sh" #脚本存放位置
internal 2 #执行时间(周期,单位:秒)
}
vrrp_instance DB {
state MASTER #这里主节点为 MASTER,其余的节点(备用节点)修改为 BACKUP
interface ens33 #网卡名称根据实际情况修改
virtual_router_id 51#同一组高可用集群中的所有节点必须设置相同的 ID,不同集群必须使用不同的 ID。
priority 200 #节点的权重,主节点需要大于备用节点(数字越大,权重越高,优先级越高)
advert_int 1
authentication {
auth_type PASS
auth_pass 123456#同一集群中的所有节点必须使用相同的密码。
}
virtual_ipaddress {
192.168.48.90 #漂移地址,主备节点一致
}
track_script {
check_mysql
}
}
EOF
node02
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
vrrp_mcast_group4 224.0.0.18
}
vrrp_script check_mysql {
script "/etc/keepalived/mysql_check.sh" #脚本存放位置
internal 2 #执行时间(周期,单位:秒)
}
vrrp_instance DB {
state BACKUP#这里主节点为 MASTER,其余的节点(备用节点)修改为 BACKUP
interface ens33 #网卡名称根据实际情况修改
virtual_router_id 51#同一组高可用集群中的所有节点必须设置相同的 ID,不同集群必须使用不>
同的 ID。
priority 100 #节点的权重,主节点需要大于备用节点(数字越大,权重越高,优先级越高)
advert_int 1
authentication {
auth_type PASS
auth_pass 123456#同一集群中的所有节点必须使用相同的密码。
}
virtual_ipaddress {
192.168.48.90 #漂移地址,主备节点一致
}
track_script {
check_mysql
}
}
EOF
4. 启动keepalived
node01&node02
systemctl start keepalived
systemctl enable keepalived
5. 验证故障转移
查看node01是否存在漂移IP
[root@node01 ~]# ip addr show ens33 | grep 192.168.48.90
inet 192.168.48.90/32 scope global ens33
node01关闭mysql,node02查看漂移IP是否到node02。
[root@node01 ~]# systemctl stop mysqld
[root@node02 ~]# ip addr show ens33 | grep 192.168.48.90
inet 192.168.48.90/32 scope global ens33
使用其他主机连接数据库的VIP。连接正常则为成功。
[root@test ~]# mysql -u root -h 192.168.48.90 -P 3306 -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.43 MySQL Community Server - GPL
到此,mysql双机热备(主主模式)完成。