MySQL 主从架构中的使用技巧及优化

MySQL 主从架构中的使用技巧及优化

文档说明

本文档基于实际操作经验,对延迟复制和慢查询日志进行了系统性优化和扩展,补充了更多实用技巧和生产级最佳实践。


第一部分:延迟复制

1.1 什么是延迟复制

延迟复制是指设置从库故意落后于主库一定时间(如10秒、1小时等),主要用于:

  • 误操作防护:主库误删除数据,可在延迟窗口内恢复
  • 故障回溯:提供时间点恢复能力
  • 读负载分离:不影响实时查询需求

1.2 配置延迟复制

MySQL 8.0+ 语法

sql

复制代码
-- 停止复制
STOP REPLICA;

-- 设置延迟时间(单位:秒)
CHANGE REPLICATION SOURCE TO SOURCE_DELAY = 10;

-- 启动复制
START REPLICA;

-- 验证配置
SHOW REPLICA STATUS\G
MySQL 5.7 及以下语法

sql

复制代码
STOP SLAVE;
CHANGE MASTER TO MASTER_DELAY = 10;
START SLAVE;
SHOW SLAVE STATUS\G

1.3 验证延迟配置

sql

复制代码
mysql> SHOW SLAVE STATUS\G
字段 说明
SQL_Delay 设置的延迟秒数
SQL_Remaining_Delay 剩余延迟秒数(正在等待时显示)

1.4 延迟复制测试

步骤1:查看当前数据

sql

复制代码
mysql> SELECT * FROM baibai.userlist;
+-------+--------+
| name  | passwd |
+-------+--------+
| swp   | 123    |
| user2 | 123    |
+-------+--------+
2 rows in set (0.00 sec)

步骤2:在主库执行删除操作

sql

复制代码
mysql> DELETE FROM baibai.userlist WHERE name='swp';
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM baibai.userlist;
+-------+--------+
| name  | passwd |
+-------+--------+
| user2 | 123    |
+-------+--------+
1 row in set (0.00 sec)

步骤3:在无延迟从库查看(已同步)

bash

复制代码
[root@mysql3 ~]# mysql -uroot -proot -e 'SELECT * FROM baibai.userlist;'
+-------+--------+
| name  | passwd |
+-------+--------+
| user2 | 123    |
+-------+--------+

步骤4:在延迟从库查看(延迟窗口内数据未变)

sql

复制代码
mysql> SELECT * FROM baibai.userlist;
+-------+--------+
| name  | passwd |
+-------+--------+
| swp   | 123    |
| user2 | 123    |
+-------+--------+
2 rows in set (0.00 sec)

步骤5:等待延迟时间过后再次查看

sql

复制代码
mysql> SELECT * FROM baibai.userlist;
+-------+--------+
| name  | passwd |
+-------+--------+
| user2 | 123    |
+-------+--------+
1 row in set (0.00 sec)

1.5 延迟复制的常见应用场景

场景 延迟时间建议 说明
防误删除 10-30分钟 给DBA留出反应时间
报表统计 1-6小时 使用延迟从库跑批,不影响主库
历史归档 24小时 保留昨日数据快照
审计合规 0(实时) 按需配置

1.6 延迟复制管理命令

sql

复制代码
-- 修改延迟时间
STOP REPLICA;
CHANGE REPLICATION SOURCE TO SOURCE_DELAY = 300;  -- 改为5分钟
START REPLICA;

-- 取消延迟(恢复实时同步)
STOP REPLICA;
CHANGE REPLICATION SOURCE TO SOURCE_DELAY = 0;
START REPLICA;

-- 查看当前延迟状态
SHOW REPLICA STATUS\G | grep -E "SQL_Delay|SQL_Remaining_Delay"

-- 临时停止延迟从库的SQL线程(保留IO线程)
STOP REPLICA SQL_THREAD;

-- 恢复
START REPLICA SQL_THREAD;

1.7 延迟复制注意事项

⚠️ 重要提醒

  • 延迟从库的 Seconds_Behind_Master 会显示延迟值,不是故障
  • 延迟期间主库的 binlog 不会被清理(从库未读取)
  • 长时间延迟可能导致 binlog 占用大量磁盘空间
  • 建议配合 expire_logs_days 设置合理的 binlog 保留时间

第二部分:慢查询日志

2.1 慢查询日志基础

慢查询日志记录执行时间超过阈值的 SQL 语句,是性能优化的核心工具。

2.2 查看慢查询配置

sql

复制代码
-- 查看慢查询相关变量
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 |
+---------------------+----------------------------------+

-- 查看慢查询阈值
mysql> SHOW VARIABLES LIKE 'long%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+

-- 查看是否记录未使用索引的查询
mysql> SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | OFF   |
+-------------------------------+-------+

2.3 开启慢查询日志

sql

复制代码
-- 开启慢查询日志
mysql> SET GLOBAL slow_query_log = ON;

-- 设置阈值(单位:秒)
mysql> SET GLOBAL long_query_time = 4;

-- 记录未使用索引的查询(建议开启)
mysql> SET GLOBAL log_queries_not_using_indexes = ON;

-- 记录全表扫描的查询
mysql> SET GLOBAL log_slow_admin_statements = ON;

-- 验证配置
mysql> SHOW VARIABLES LIKE 'slow%';
mysql> SHOW VARIABLES LIKE 'long%';

2.4 测试慢查询日志

sql

复制代码
-- 执行短查询(低于阈值,不会记录)
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)

2.5 查看慢查询日志

bash

复制代码
# 查看慢查询日志内容
[root@mysql-node1 ~]# cat /data/mysql/mysql-node1-slow.log

日志输出示例:

text

复制代码
/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);

2.6 慢查询日志分析工具

mysqldumpslow(MySQL 自带)

bash

复制代码
# 按查询时间排序,查看最慢的10条
mysqldumpslow -s t -t 10 /data/mysql/mysql-node1-slow.log

# 按平均查询时间排序
mysqldumpslow -s at -t 10 /data/mysql/mysql-node1-slow.log

# 按查询次数排序
mysqldumpslow -s c -t 10 /data/mysql/mysql-node1-slow.log

# 显示详细的查询语句
mysqldumpslow -a /data/mysql/mysql-node1-slow.log
pt-query-digest(Percona Toolkit)

bash

复制代码
# 安装
yum install percona-toolkit -y

# 分析慢查询日志
pt-query-digest /data/mysql/mysql-node1-slow.log

# 输出到文件
pt-query-digest /data/mysql/mysql-node1-slow.log > slow_query_report.txt

# 分析多个日志文件
pt-query-digest /data/mysql/mysql-node1-slow.log /data/mysql/mysql-node2-slow.log

2.7 生产环境配置建议

sql

复制代码
-- 永久生效配置(写入 my.cnf)
[mysqld]
# 慢查询日志
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow-query.log
long_query_time = 2                    # 建议2秒
log_queries_not_using_indexes = ON     # 记录未使用索引的查询
log_slow_admin_statements = ON         # 记录慢管理语句
log_slow_slave_statements = ON         # 记录从库慢查询

# 慢查询日志轮转
slow_query_log_rotate_size = 100M      # 日志文件达到100M时轮转

2.8 慢查询日志轮转配置

bash

复制代码
#!/bin/bash
# /etc/logrotate.d/mysql-slow
/data/mysql/mysql-slow.log {
    daily
    rotate 30
    missingok
    notifempty
    compress
    delaycompress
    sharedscripts
    postrotate
        # 重新打开日志文件
        mysql -e "SET GLOBAL slow_query_log = OFF; SET GLOBAL slow_query_log = ON;"
    endscript
}

第三部分:主从架构高级技巧

3.1 跳过特定数据库的复制

sql

复制代码
-- 在从库配置(my.cnf)
[mysqld]
replicate_ignore_db = mysql           # 忽略 mysql 库
replicate_ignore_db = performance_schema
replicate_do_db = baibai              # 只复制 baibai 库

-- 动态修改
CHANGE REPLICATION FILTER 
    REPLICATE_DO_DB = (baibai),
    REPLICATE_IGNORE_DB = (mysql, performance_schema);

3.2 并行复制优化

sql

复制代码
-- 查看当前并行复制配置
SHOW VARIABLES LIKE 'slave_parallel%';

-- 设置并行复制(MySQL 5.7+)
SET GLOBAL slave_parallel_workers = 4;
SET GLOBAL slave_parallel_type = LOGICAL_CLOCK;

-- 永久配置(my.cnf)
[mysqld]
slave_parallel_workers = 4
slave_parallel_type = LOGICAL_CLOCK

3.3 半同步复制

sql

复制代码
-- Master 配置
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;

-- Slave 配置
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;

-- 查看状态
SHOW STATUS LIKE 'Rpl_semi_sync%';

3.4 GTID 复制模式

sql

复制代码
-- 启用 GTID(my.cnf)
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON

-- 使用 GTID 配置复制
CHANGE MASTER TO
    MASTER_HOST='172.25.254.10',
    MASTER_USER='swp',
    MASTER_PASSWORD='swp',
    MASTER_AUTO_POSITION = 1;

第四部分:监控与告警

4.1 复制延迟监控

sql

复制代码
-- 实时监控延迟
SELECT 
    TIMEDIFF(NOW(), last_timestamp) AS delay
FROM performance_schema.replication_applier_status_by_worker;

-- 监控复制状态
SELECT 
    SERVICE_STATE AS io_thread,
    LAST_ERROR_NUMBER,
    LAST_ERROR_MESSAGE
FROM performance_schema.replication_connection_status;

4.2 告警脚本

bash

复制代码
#!/bin/bash
# check_replication_delay.sh

THRESHOLD=60  # 延迟告警阈值(秒)

DELAY=$(mysql -uroot -proot -e "SHOW SLAVE STATUS\G" | grep "Seconds_Behind_Master:" | awk '{print $2}')

if [ "$DELAY" = "NULL" ] || [ "$DELAY" -gt "$THRESHOLD" ]; then
    echo "WARNING: Replication delay is ${DELAY}s"
    # 发送告警(邮件、钉钉、微信等)
    # curl -X POST "https://your-webhook-url" -d "{\"msg\":\"MySQL复制延迟: ${DELAY}s\"}"
else
    echo "OK: Replication delay is ${DELAY}s"
fi

第五部分:故障处理速查表

问题 现象 解决方案
复制中断 Slave_SQL_Running: No STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;
IO线程停止 Slave_IO_Running: No 检查网络、权限、binlog是否存在
延迟过大 Seconds_Behind_Master 持续增长 检查从库性能,考虑并行复制
主键冲突 1062错误 跳过或删除重复数据
数据不一致 主从数据不同 使用 pt-table-checksum 检查和修复

附录:快速命令参考

sql

复制代码
-- 延迟复制
STOP SLAVE; CHANGE MASTER TO MASTER_DELAY=10; START SLAVE; SHOW SLAVE STATUS\G

-- 慢查询日志
SET GLOBAL slow_query_log=ON; SET GLOBAL long_query_time=2;

-- 查看复制状态
SHOW SLAVE STATUS\G | grep -E "Running|Delay|Behind"

-- 跳过复制错误
STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE;

-- 查看 binlog 文件
SHOW BINARY LOGS;
SHOW MASTER STATUS;
相关推荐
羊小蜜.2 小时前
Mysql 11: 存储过程全解——从创建到使用
android·数据库·mysql·存储过程
宠友信息2 小时前
社交软件源码哪个渠道好
java·微服务·架构·社交电子·springboot·uniapp
chaofan9802 小时前
2026大模型应用架构选型:如何通过API聚合平台构建企业级AI服务?
人工智能·架构·自动化·api
zh_xuan2 小时前
Android compose和传统view混用
android
jjjava2.02 小时前
MySQL索引原理与优化实战
mysql
阿丰资源2 小时前
java项目-基于SpringBoot+MySQL+Vue的前后端分离宠物商店系统(附资料)
java·spring boot·mysql
大黄说说2 小时前
MySQL索引失效的常见场景有哪些?如何通过EXPLAIN分析查询性能?
android·adb
冰糖葫芦三剑客2 小时前
华为 Android APP 应用内生成合成内容的文件元数据中添加隐式标识的截图 开发要怎么生成?
android·华为
沐雪轻挽萤2 小时前
ROS 架构深度解析与工程实践
架构