如何处理 MySQL 主从延迟?


MySQL 读写分离在互联网项目中其实还是比较常见的,松哥之前也写过文章和大家介绍具体的搭建方案,还不会搭建的小伙伴可以参考这里:

既然是主从,是读写分离,那就不可避免会产生延迟,因为数据从主机同步到从机,总是需要时间的。

一般来说这个时间不会太久,可能就是 1ms 左右。

不过,如果你的系统数据量比较大,亦或者业务对数据实时性要求比较高,那么我们还是需要想办法去处理这个主从延迟。

一般来说有如下几种思路,松哥来和大家一一说明。

一 强制读主库

第一种方案就是强制读主库。

这种方案看着有点笨重,但却是我司用的最多的一种方案。

简单来说,就是将查询请求进行分类:一类是对数据实时性要求不高的请求,这种请求直接去读从库;另一类则是对实时性要求比较高的请求,这种就强制读主库。

举个简单例子:读取系统配置、读取用户基本信息等等,都算是对数据实时性要求不高的请求,这种直接读取从库就可以了;但是像用户下单获取订单状态的话,这种就需要读主库了,确保数据的一致性。

强制读主库我们可以在代码里边通过 AOP 的方式实现,也可以通过一些数据库中间如 ShardingJDBC 去配置。

二 sleep 方案

这种方案就是刚刚插入完成之后,此时如果去读取从机的话,先 sleep 一会再读,这样就能尽量保证从机的数据已经同步过来了。

不过这个方案显然不够优雅,发请求先 sleep,怎么想都觉得别扭。

三 判断主从是否延迟

第三种方案就是我们去判断一下主从是否延迟,如果发生延迟了,就等一会,如果数据已经同步了,那就直接查询就行了。

判断是否发生主从延迟,一般来说可以通过两种方式。

3.1 seconds_behind_master

seconds_behind_master 参数是一个只读变量,用于表示从服务器(slave)相对于主服务器(master)的复制延迟时间。

这个参数反映了从服务器在复制过程中落后于主服务器的时间长度(以秒为单位)。

这个参数的取值如下:

  1. 正值:表示从服务器正在追赶主服务器的复制进度。具体的数值表示从属服务器的复制进程落后于主服务器的时间长度。例如,如果此值为 60 秒,那么意味着从服务器的复制操作比主服务器晚了 60 秒。
  2. 0:表示从属服务器与主服务器的复制同步是实时的,没有延迟。这意味着从属服务器已经完成了所有可用的复制事件,且没有新的事件等待应用。
  3. NULL
    • 如果从服务器刚刚启动,还没有开始复制过程,那么此值可能是 NULL。
    • 如果从服务器与主服务器之间的连接断开,或者从属服务器正在处理非复制任务(例如,正在进行表修复),也可能显示为 NULL。
    • 如果从服务器已经追上了主服务器,并且没有新的事件需要复制,也会显示为 NULL。

要查看 seconds_behind_master 的值,我们可以使用以下 SQL 命令:

SHOW SLAVE STATUS\G;

输出中会有一行显示 Seconds_Behind_Master,这就是你要找的信息。

利用 seconds_behind_master 参数,我们可以监控复制延迟,管理员可以据此了解从服务器的复制进度,并确定是否存在复制延迟问题。

在 MySQL8.0 之后的版本中,seconds_behind_master 被替换为 replication_lag,但这两个参数的功能是一样的。

3.2 GTID

GTID 是 MySQL5.6 引入的一个特性,用于跟踪事务在主服务器上的执行情况,并确保这些事务按顺序在从服务器上重现。使用 GTID 进行主从复制可以简化管理和监控,特别是在有多个从服务器或复杂的复制拓扑中。

下面松哥给大家简单演示下如何利用 GTID 判断 MySQL 主从复制是否发生延迟。

步骤 1:确认主服务器和从服务器都启用了 GTID

确保主服务器和从服务器都配置了 GTID。需要在 MySQL 的配置文件(如 my.cnfmy.ini)中设置 server-idgtid_mode

[mysqld]
server-id       = 1  # 主服务器的 server-id
gtid_mode       = ON  # 启用 GTID
[mysqld]
server-id       = 2  # 从服务器的 server-id
gtid_mode       = ON  # 启用 GTID
步骤 2:检查 GTID 执行状态

可以使用 SHOW MASTER STATUSSHOW SLAVE STATUS 命令来检查主服务器和从服务器的 GTID 状态。

在主服务器上
SHOW MASTER STATUS;

这里多说一句,从 MySQL8.4 开始,不再使用 SHOW MASTER STATUS;,取而代之的是 SHOW BINARY LOG STATUS

输出将包括当前的 GTID 执行位置,如下所示:

File: mysql-bin.000001
Position: 107
Binlog_Do_DB: 
Binlog_Ignore_DB: 
Executed_Gtid_Set: 11111111-1111-1111-1111-111111111111:1-100

这里 Executed_Gtid_Set 显示了主服务器已经执行的所有 GTID 的集合。

在从服务器上
SHOW SLAVE STATUS\G;

输出将包括从服务器的 GTID 执行位置,如下所示:

...
Master_Host: master.example.com
Master_User: replication
Master_Port: 3306
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 107
Relay_Master_Log_File: mysql-bin.000001
...
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: 107
Auto_Position: 1
...

其中 Auto_Position 的值为 1 表示从服务器正在使用 GTID 进行复制。

步骤 3:比较 GTID 集合

比较主服务器和从服务器的 Executed_Gtid_Set。如果两者相同,则表示复制没有延迟;如果有差异,则表示存在延迟。

步骤 4:分析 GTID 集合差异

如果发现 GTID 集合之间存在差异,可以通过以下命令查看具体的 GTID:

SELECT @@gtid_executed;

通过比较主从上两个命令执行的结果,就可以知道是否发生了延迟。如果发生了延迟,我们就停一会再去读。

松哥这边的项目第一种方案是使用比较多的,另外两种使用相对比较少。小伙伴们有无遇到类似问题,都是怎么解决的?欢迎留言讨论。

<think>嗯,用户想解决MySQL主从同步延迟的问题,需要排查和解决。首先,我得回想一下主从复制的基本原理,然后考虑可能导致延迟的各种原因。根据之前学过的知识,主从复制延迟可能有多个方面,比如硬件资源不足、配置问题、大事务、慢查询、主库高并发等等。 首先,用户可能需要检查硬件资源,比如主从库的CPU、磁盘IO、网络带宽是否足够。如果主库的磁盘IO慢,或者从库的硬件较差,都可能导致延迟。比如,如果主库使用SSD而从库用机械硬盘,那从库处理日志的速度可能跟不上主库。 然后,配置方面,尤其是MySQL的版本。低版本可能只支持单线程复制,而高版本支持多线程复制(比如基于库、表或行的并行复制)。需要确认用户使用的MySQL版本,如果版本较低,升级到支持多线程的版本可能有效。比如,引用[1]提到低版本MySQL单线程复制的问题,换成高版本支持多线程可以解决。 接着,复制线程的状态和延迟情况,可以用show slave status命令查看Seconds_Behind_Master参数。如果这个值很大,说明延迟严重。同时,检查IO线程和SQL线程是否正常运行,有没有错误信息。如果有错误,比如主键冲突或者网络中断,需要解决这些错误才能继续复制。 另外,大事务或者长事务也是一个常见原因。比如,用户执行了一个大量更新的操作,比如没有索引的DELETE语句,或者一次性插入大量数据,这些事务在从库上执行时会阻塞后续的事务,导致延迟。引用[2]提到,如果一条SQL执行20秒,从库就会延迟20秒,所以需要优化慢查询,拆分大事务。 慢查询日志也是需要检查的,找出执行时间长的SQL进行优化。比如,使用pt-query-digest分析慢日志,或者用show full processlist查看当前执行的查询。优化索引,减少锁竞争,分批次处理数据都可能有效。 主库的高并发写入也是一个因素。如果主库并发太高,从库处理不过来,可以考虑使用分片或者读写分离架构,分散压力。引用[3]提到业务层面是否能接受一定延迟,可能需要调整架构,比如将实时性要求高的查询仍然指向主库,其他查询走从库。 还有主从之间的网络延迟问题,比如跨机房同步可能会有较高的网络延迟,需要检查网络状况,使用ping或traceroute工具测试,或者考虑专线连接。 除此之外,一些参数配置也可能影响复制速度,比如sync_binlog、innodb_flush_log_at_trx_commit等。主库如果配置为双1(安全性高),可能会影响性能,而从库可能可以调整这些参数以提高复制速度,但需要权衡数据安全性。 另外,从库上的查询压力过大也可能导致延迟。如果从库同时处理大量读请求,可能会占用资源,影响SQL线程的应用速度。这时候可能需要增加从库数量,分摊读负载,或者升级从库硬件。 总结下来,排查步骤可能包括:检查硬件资源、查看复制状态、分析大事务和慢查询、优化配置、调整架构等。解决方案可能涉及升级MySQL版本、优化SQL、拆分事务、调整参数、增加从库或改善网络等。 用户可能需要分步骤来处理,先确定延迟的原因,再针对性地解决。比如,先检查Seconds_Behind_Master,然后看IO/SQL线程状态,再检查是否有慢查询或大事务,接着评估硬件和配置是否合理,最后考虑架构调整。每一步都需要具体的命令或工具支持,比如show slave status、查看进程列表、分析慢日志等。 可能还需要考虑是否使用了并行复制,以及并行复制的配置是否正确。例如,在MySQL 5.6之后支持基于库的并行复制,而5.7及更高版本支持基于逻辑时钟的并行复制,可以更高效地处理事务。 总的来说,解决主从延迟需要多方面的分析和调整,用户可能需要结合监控工具和日志分析来定位问题,然后逐步优化。</think>### 排查和解决MySQL主从复制延迟问题的步骤 #### 一、排查延迟原因 1. **检查主从复制状态** 执行 `SHOW SLAVE STATUS\G`,关注以下关键字段: - `Seconds_Behind_Master`:表示从库落后主库的时间(秒)。若为0则表示无延迟,若为`NULL`可能表示复制中断[^3]。 - `Slave_IO_Running` 和 `Slave_SQL_Running`:确认两个线程是否正常运行。 - `Last_Error`:检查是否有复制错误(如主键冲突、表不存在等)。 2. **分析硬件和网络资源** - **主从库硬件性能**:从库硬件配置(CPU、磁盘IO)若低于主库,可能导致应用日志速度慢[^1]。 - **网络延迟**:通过 `ping` 或 `traceroute` 检测主从库之间的网络延迟。跨机房同步时,建议使用专线或优化网络路径。 3. **识别大事务和慢查询** - 主库执行 `SHOW FULL PROCESSLIST`,检查是否有长时间运行的事务或锁等待。 - 分析从库的慢查询日志(`slow_query_log`),优化执行时间长的SQL语句[^2]。 - 大事务(如无索引的批量删除)会阻塞复制,需拆分为小事务[^2]。 --- #### 二、针对性解决方案 1. **升级MySQL版本** 低版本仅支持单线程复制,高版本(如MySQL 5.6+)支持多线程复制(参数 `slave_parallel_workers`),可显著提升从库处理效率。 2. **优化慢查询和大事务** - 通过 `EXPLAIN` 分析慢查询,添加索引或重构SQL。 - 将批量操作拆分为多次提交(例如:`INSERT INTO ... VALUES (...), (...);` 改为分批次插入)。 3. **调整复制配置** - **启用并行复制**(MySQL 5.7+): ```sql SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK'; SET GLOBAL slave_parallel_workers = 4; -- 根据CPU核心数调整 ``` - **减少主库写入压力**: 主库设置 `sync_binlog=0` 和 `innodb_flush_log_at_trx_commit=2`(牺牲部分安全性换取性能)。 4. **读写分离与架构优化** - 实时性要求高的查询直连主库,其他查询走从库。 - 增加从库数量,分摊读负载。 5. **监控与告警** 使用工具(如Percona Monitoring、Prometheus)监控 `Seconds_Behind_Master`,设置阈值告警。 --- #### 三、操作示例 1. **查看复制延迟** ```sql SHOW SLAVE STATUS\G -- 关注 Seconds_Behind_Master, Last_Error ``` 2. **优化慢SQL** ```sql -- 开启慢查询日志 SET GLOBAL slow_query_log = 'ON'; -- 分析慢查询 pt-query-digest /var/lib/mysql/slow.log ``` 3. **拆分大事务** ```sql -- 原语句(删除100万条数据) DELETE FROM logs WHERE create_time < '2020-01-01'; -- 优化为分批删除 DELETE FROM logs WHERE create_time < '2020-01-01' LIMIT 1000; -- 循环执行直至完成 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值