MySql 主从复制+Keepalived
大约 11 分钟约 3291 字
MySql 主从复制+Keepalived
安装MySql
准备节点
10.6.251.248
10.6.251.249编辑节点配置文件
1.主节点
vi /etc/my.cnf
#启用二进制日志文件
log-bin = mysql-bin # 开启二进制日志,主节点必须要开启,从节点可以不开。
server-id = 248 # 服务ID号,主从节点都需要,且要唯一,一般配置为IP地址后面几位
# 重启mysql
service mysql restart
# 查看二进制文件是否开启成功
mysql -uroot -p
SHOW GLOBAL VARIABLES LIKE '%log%';
# 查看主库信息
SHOW master STATUS;
#mysql-bin.000002
#154
2.从节点
# 修改my.cnf
vi /etc/my.cnf
log-bin = mysql-bin # 开启二进制日志,主节点必须要开启,从节点可以不开。
server-id = 249 # 服务ID号,主从节点都需要,且要唯一,一般配置为IP地址后面几位
# 重启mysql
service mysql restart
# 从库执行
mysql -uroot -p
change master to master_host='10.6.251.248',master_user='root',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;
# 填写正确的主服务器信息,账号密码信息
# master_log_file和master_log_pos用查询到主库里的信息;
# 配置完成后,启动slave服务:
start slave;
# 查看slave信息:
show slave status \G;
# Slave_IO_Running 和 Slave_SQL_Running这两项必须要全部显示为yes才可以。
# 如果上keepalived 248也需要做如下操作
#mysql -uroot -p
#change master to master_host='10.6.251.249',master_user='root',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;
# 填写正确的主服务器信息,账号密码信息
# master_log_file和master_log_pos用查询到主库里的信息;此处获取249的信息
# 配置完成后,启动slave服务:
#start slave;
# 查看slave信息:
#show slave status \G;提示
如果第二台是直接克隆的第一台的环境,此时Slave_IO_Running应该是NO
需要去安装目录修改auto.cnf的server-uuid
cd /opt/mysql/data
vi auto.cnf
service mysql restart
继续查看参数是否为Yes
mysql -uroot -p
stop slave; 停止链路
start slave; 启动链路
show slave status \G; 查看链路
操作主库,做同步验证
自行测试,建库,建表,数据更新等操作
Keepalived搭建
安装Keepalived
# 下载包
wget https://www.keepalived.org/software/keepalived-2.2.7.tar.gz
# 解压包到指定目录
tar zxvf keepalived-2.2.7.tar.gz -C /usr/local
# 进入目录
cd /usr/local
# 重命名 keepalived-2.2.7
mv keepalived-2.2.7 keepalived
# 进入keepalived目录
cd keepalived
./configure --prefix=/usr/local/keepalived
# 如有openssl错误,请执行安装
yum -y install openssl openssl-devel
# 安装完成后再 ./configure --prefix=/usr/local/keepalived
#安装
make && make install
# 启动脚本拷贝到/etc/init.d,方便用service命令进行操作
cp /usr/local/keepalived/keepalived/etc/init.d/keepalived /etc/init.d/keepalived
ll /etc/init.d/ | grep keepalived
pidfile: /var/run/keepalived.pid
config: /etc/keepalived/keepalived.conf
#把配置文件移动到启动应用默认找的路径/etc/keepalived/keepalived.conf
mkdir -p /etc/keepalived
mv /usr/local/keepalived/etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf主库配置
rm /etc/keepalived/keepalived.conf
vi /etc/keepalived/keepalived.conf
#配置内容如下
global_defs {
router_id MySQL-HA
}
vrrp_script check_run {
script "/opt/mysql/mysql_check.sh" #此文件待会创建
interval 60
}
vrrp_sync_group VG1 {
group {
VI_1
}
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 100
advert_int 1
nopreempt
track_script {
check_run
}
notify_master /opt/mysql/master.sh
notify_stop /opt/mysql/stop.sh
virtual_ipaddress {
10.6.251.247
}
}编写/opt/mysql/mysql_check.sh
vi /opt/mysql/mysql_check.sh
# 内容
#!/bin/bash
count=1
while true
do
mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show status;" > /dev/null 2>&1
i=$?
ps aux | grep mysqld | grep -v grep > /dev/null 2>&1
j=$?
if [ $i = 0 ] && [ $j = 0 ]
then
exit 0
else
if [ $i = 1 ] && [ $j = 0 ]
then
exit 0
else
if [ $count -gt 5 ]
then
break
fi
let count++
continue
fi
fi
done
/etc/init.d/keepalived stop编写/opt/mysql/master.sh
vi /opt/mysql/master.sh
# 内容
#!/bin/bash
Master_Log_File=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show slave status\G" | grep -w Master_Log_File | awk -F": " '{print $2}')
Relay_Master_Log_File=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show slave status\G" | grep -w Relay_Master_Log_File | awk -F": " '{print $2}')
Read_Master_Log_Pos=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show slave status\G" | grep -w Read_Master_Log_Pos | awk -F": " '{print $2}')
Exec_Master_Log_Pos=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show slave status\G" | grep -w Exec_Master_Log_Pos | awk -F": " '{print $2}')
i=1
while true
do
if [ $Master_Log_File = $Relay_Master_Log_File ] && [ $Read_Master_Log_Pos -eq $Exec_Master_Log_Pos ]
then
echo "ok"
break
else
sleep 1
if [ $i -gt 60 ]
then
break
fi
continue
let i++
fi
done
mysql -uroot -p1111111 -S /tmp/mysql.sock -e "stop slave;"
mysql -uroot -p1111111 -S /tmp/mysql.sock -e "reset slave all;"
mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show master status;" > /tmp/master_status_$(date "+%y%m%d-%H%M").txt编写/opt/mysql/stop.sh
vi /opt/mysql/stop.sh
#内容
#!/bin/bash
M_File1=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show master status\G" | awk -F': ' '/File/{print $2}')
M_Position1=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show master status\G" | awk -F': ' '/Position/{print $2}')
sleep 1
M_File2=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show master status\G" | awk -F': ' '/File/{print $2}')
M_Position2=$(mysql -uroot -p1111111 -S /tmp/mysql.sock -e "show master status\G" | awk -F': ' '/Position/{print $2}')
i=1
while true
do
if [ $M_File1 = $M_File1 ] && [ $M_Position1 -eq $M_Position2 ]
then
echo "ok"
break
else
sleep 1
if [ $i -gt 60 ]
then
break
fi
continue
let i++
fi
done启动keepalived
service keepalived start #启动
service keepalived stop #停止
service keepalived restart #重启从库配置,同主库配置
# 安装Keepalived 同主库
# 编写/opt/mysql/mysql_check.sh 同主库
# 编写/opt/mysql/master.sh 同主库
# 编写/opt/mysql/stop.sh 同主库从库/etc/keepalived/keepalived.conf配置
rm /etc/keepalived/keepalived.conf
vi /etc/keepalived/keepalived.conf
# 内容
global_defs {
router_id MySQL-HA
}
vrrp_script check_run {
script "/opt/mysql/mysql_check.sh" #此文件待会创建
interval 60
}
vrrp_sync_group VG1 {
group {
VI_1
}
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
nopreempt
track_script {
check_run
}
notify_master /opt/mysql/master.sh
notify_stop /opt/mysql/stop.sh
virtual_ipaddress {
10.6.251.247
}
}启动keepalived
service keepalived start #启动
service keepalived stop #停止
service keepalived restart #重启验证 keepalived
使用10.6.251.247 虚拟ip连接

1.杀死主库进程,看是否依然能正常操作数据库
pkill -9 mysqld
2.启动主库,杀死从库,互相测试
service mysql start
主从复制原理与排障
复制线程模型
MySQL 主从复制涉及三个核心线程:
主库:
Binlog Dump Thread — 负责将 binlog 事件发送给从库
|
| binlog events
v
从库:
IO Thread — 接收 binlog 事件,写入 relay log
|
| relay log
v
SQL Thread — 读取 relay log,重放 SQL 语句
同步流程:
1. 主库执行事务,写入 binlog
2. 从库 IO Thread 连接主库,请求 binlog
3. 主库 Binlog Dump Thread 读取 binlog 发送给从库
4. 从库 IO Thread 将事件写入 relay log
5. 从库 SQL Thread 读取 relay log 并执行
6. 从库更新自己的 binlog(如果开启了 log-slave-updates)常见复制问题与解决
# 问题 1:Slave_IO_Running: No
# 原因:网络不通、主库 binlog 被删除、server-id 冲突
# 排查步骤
# 1. 检查网络连通性
ping 10.6.251.248
telnet 10.6.251.248 3306
# 2. 检查主库状态
mysql -uroot -p -e "SHOW MASTER STATUS;"
# 3. 检查从库错误信息
mysql -uroot -p -e "SHOW SLAVE STATUS \G;" | grep Last_IO_Error
# 4. 常见修复 — 重新指定 binlog 位置
STOP SLAVE;
CHANGE MASTER TO
master_log_file='mysql-bin.000003',
master_log_pos=154;
START SLAVE;
# 问题 2:Slave_SQL_Running: No
# 原因:SQL 执行错误(主键冲突、数据不存在等)
# 排查步骤
mysql -uroot -p -e "SHOW SLAVE STATUS \G;" | grep Last_SQL_Error
# 方案 A:跳过错误(谨慎使用)
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;
# 方案 B:修复数据后重启
STOP SLAVE;
# 手动修复从库数据
START SLAVE;
# 问题 3:复制延迟过大
# 检查延迟秒数
mysql -uroot -p -e "SHOW SLAVE STATUS \G;" | grep Seconds_Behind_Master
# 减少延迟的方法:
# 1. 开启多线程复制
STOP SLAVE;
SET GLOBAL slave_parallel_workers = 4;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
START SLAVE;
# 2. 开启半同步复制(比异步更可靠)
# 主库安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 3000; # 3 秒超时
# 从库安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
STOP SLAVE; START SLAVE;复制监控脚本
#!/bin/bash
# mysql_replication_monitor.sh — 主从复制监控脚本
MYSQL_USER="root"
MYSQL_PASS="1111111"
ALERT_EMAIL="admin@example.com"
MAX_DELAY=60 # 最大允许延迟(秒)
# 检查复制状态
SLAVE_STATUS=$(mysql -u$MYSQL_USER -p$MYSQL_PASS -e "SHOW SLAVE STATUS \G;" 2>/dev/null)
IO_RUNNING=$(echo "$SLAVE_STATUS" | grep "Slave_IO_Running:" | awk '{print $2}')
SQL_RUNNING=$(echo "$SLAVE_STATUS" | grep "Slave_SQL_Running:" | awk '{print $2}')
BEHIND=$(echo "$SLAVE_STATUS" | grep "Seconds_Behind_Master:" | awk '{print $2}')
# 检查 IO 线程
if [ "$IO_RUNNING" != "Yes" ]; then
ERROR=$(echo "$SLAVE_STATUS" | grep "Last_IO_Error:" | cut -d':' -f2-)
echo "告警:Slave IO 线程停止!错误: $ERROR"
# echo "Slave IO stopped: $ERROR" | mail -s "MySQL 复制告警" $ALERT_EMAIL
fi
# 检查 SQL 线程
if [ "$SQL_RUNNING" != "Yes" ]; then
ERROR=$(echo "$SLAVE_STATUS" | grep "Last_SQL_Error:" | cut -d':' -f2-)
echo "告警:Slave SQL 线程停止!错误: $ERROR"
fi
# 检查延迟
if [ "$BEHIND" != "NULL" ] && [ "$BEHIND" -gt "$MAX_DELAY" ]; then
echo "告警:复制延迟 ${BEHIND} 秒,超过阈值 ${MAX_DELAY} 秒"
fi
echo "IO: $IO_RUNNING | SQL: $SQL_RUNNING | Delay: ${BEHIND}s"
# 添加到 crontab(每分钟检查一次)
# */1 * * * * /opt/mysql/mysql_replication_monitor.sh >> /var/log/mysql_replication.log 2>&1数据一致性校验
# 使用 pt-table-checksum 和 pt-table-sync 校验数据一致性
# 安装 Percona Toolkit
yum install -y percona-toolkit
# 在主库上执行校验(检查所有表)
pt-table-checksum \
--host=10.6.251.248 \
--user=root \
--password=1111111 \
--databases=myapp \
--no-check-binlog-format \
--replicate=percona.checksums
# 查看校验结果
mysql -uroot -p -e "SELECT * FROM percona.checksums WHERE master_cnt <> this_cnt OR master_crc <> this_crc;"
# 如果发现不一致,使用 pt-table-sync 修复
pt-table-sync \
--print \
--host=10.6.251.248 \
--user=root \
--password=1111111 \
10.6.251.249
# 实际执行修复(去掉 --print 加 --execute)
# pt-table-sync --execute h=10.6.251.248 h=10.6.251.249关键知识点
GTID 复制(推荐方式)
GTID(Global Transaction Identifier)是 MySQL 5.6+ 引入的复制方式,比传统的 binlog + position 方式更可靠。
# 启用 GTID(在 my.cnf 中添加)
# 主库和从库都需要配置
gtid_mode = ON
enforce_gtid_consistency = ON
log_slave_updates = ON
# 重启 MySQL
service mysql restart
# 使用 GTID 配置从库(无需指定 binlog 文件和位置)
mysql -uroot -p
CHANGE MASTER TO
master_host='10.6.251.248',
master_user='root',
master_password='123456',
master_auto_position=1; -- 使用 GTID 自动定位
START SLAVE;
SHOW SLAVE STATUS \G;
# GTID 的优势:
# 1. 不需要手动指定 binlog 文件和位置
# 2. 主从切换更简单
# 3. 复制中断后自动跳过已执行的事务
# 4. 便于验证主从数据一致性
# 查看已执行的 GTID
SHOW GLOBAL VARIABLES LIKE 'gtid_executed';
# 主从切换(在新的主库上执行)
STOP SLAVE;
RESET MASTER; -- 清空从库状态
# 其他从库指向新主库
CHANGE MASTER TO
master_host='新主库IP',
master_auto_position=1;
START SLAVE;MySQL 读写分离配置
# 使用 Keepalived VIP 实现简单的读写分离
# 写操作 — 连接主库(10.6.251.248)
# 读操作 — 连接 VIP(10.6.251.247)或从库(10.6.251.249)
# 方案 1:应用层控制
# 写操作直接连接主库
# 读操作连接从库
# 适用于大多数场景
# 方案 2:使用 MySQL Router 或 ProxySQL
# 安装 ProxySQL
yum install -y proxysql
# 配置 ProxySQL 实现自动读写分离
# /etc/proxysql.cnf
# 将写请求路由到主库
# 将读请求路由到从库
# 方案 3:使用 MyCat 中间件
# 配置 schema.xml 和 rule.xml
# 实现透明的读写分离
# 应用层连接字符串示例
# 写连接:Server=10.6.251.248;Database=myapp;User=root;Password=123456
# 读连接:Server=10.6.251.249;Database=myapp;User=root;Password=123456备份与恢复策略
# 全量备份(在主库上执行)
mysqldump -uroot -p --single-transaction --master-data=2 \
--all-databases --flush-logs > /backup/full_backup_$(date +%Y%m%d).sql
# 增量备份(通过 binlog)
# 查看当前 binlog 文件列表
mysql -uroot -p -e "SHOW BINARY LOGS;"
# 备份 binlog 文件
mysqlbinlog --read-from-remote-server --host=10.6.251.248 \
--user=root --password=123456 \
mysql-bin.000001 mysql-bin.000002 \
> /backup/incremental_$(date +%Y%m%d).sql
# 恢复步骤
# 1. 恢复全量备份
mysql -uroot -p < /backup/full_backup_20240101.sql
# 2. 恢复增量备份(按顺序应用 binlog)
mysql -uroot -p < /backup/incremental_20240102.sql
# 3. 重建从库复制
CHANGE MASTER TO
master_host='10.6.251.248',
master_user='root',
master_password='123456',
master_auto_position=1;
START SLAVE;- 部署类主题的核心不是“装成功”,而是“稳定运行、可排障、可回滚”。
- 同一个服务通常至少要关注版本、目录、端口、权限、数据、日志和备份。
- Linux 问题经常跨越系统层、网络层、服务层和应用层。
- 先把数据模型、访问模式和执行代价绑定起来理解。
项目落地视角
- 把安装步骤补成可重复执行的清单,必要时写成脚本或配置文件。
- 把配置目录、数据目录、日志目录和挂载点明确拆开。
- 上线前检查防火墙、SELinux、时区、磁盘、系统服务和健康检查。
- 保留执行计划、样本 SQL、索引定义和优化前后指标。
常见误区
- 使用 latest 或未固定版本,导致环境不可复现。
- 只验证启动成功,不验证持久化、开机自启和故障恢复。
- 遇到问题先改配置而不是先看日志和依赖链路。
- 脱离真实数据分布设计索引。
进阶路线
- 继续补齐 systemd、性能监控、安全加固和备份恢复。
- 把单机操作升级成 Docker、Kubernetes 或 IaC 方案。
- 建立标准化运维手册,包括巡检、扩容、回滚和灾备演练。
- 继续深入存储引擎、复制机制、归档与冷热分层治理。
适用场景
- 当你准备把《MySql 主从复制+Keepalived》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合单机环境初始化、中间件快速搭建、测试环境验证和生产部署前准备。
- 当服务稳定性依赖端口、权限、目录、网络和系统参数时,这类主题会直接影响成败。
落地建议
- 固定版本号与镜像标签,避免“latest”带来的不可预期变化。
- 把配置、数据、日志目录拆开管理,并记录恢复步骤。
- 上线前确认端口、防火墙、SELinux、时区和磁盘空间。
排错清单
- 先查 systemctl、容器日志和应用日志,确认失败发生在哪一层。
- 检查端口占用、目录权限、挂载路径和网络连通性。
- 如果是新环境问题,优先对比与已知正常环境的差异。
复盘问题
- 如果把《MySql 主从复制+Keepalived》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《MySql 主从复制+Keepalived》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《MySql 主从复制+Keepalived》最大的收益和代价分别是什么?
