如何准确获取 MySQL 主从延迟时间?

图片

作者:陈宇,现任爱可生南区项目经理,负责项目整体质量、安全、进度、成本管理的责任保证体系。对开源技术执着,为客户负责,喜欢极限运动,足球。

本文约 1600 字,预计阅读需要 6 分钟。


1背景

MySQL 5.7 已于 2023 年 10 月 EOL[1],但仍然有大量的生产环境依赖此版本。本文撰写时间 2025 年 3 月。

不久前,在一套采用 MySQL 5.7 作为部署版本的生产环境中,由于业务执行了大规模事务,进而引发了 MySQL 主从复制的延迟,最终暴露出数据一致性方面的严重问题。

由于业务做了读写分离,从库读取的数据与主库不一致,影响了应用逻辑。业务团队提出明确需求:需要知道主从延迟的具体时间值,以评估影响并优化系统。

请读者思考一下:

1. 如何获取主从延迟时间值?

2. 如何判断获取的值是准确的?

随后我们分析了 MySQL 5.7 的内置指标 Seconds_Behind_Master[2] 的可靠性,并探索更精准的替代方案。

2Seconds_Behind_Master 可靠吗?

Seconds_Behind_Master 是 SHOW SLAVE STATUS 输出中的字段,表示从库应用二进制日志事件时落后主库的秒数。

  • 理论上,值为 0 表示从库已同步,较高的值则反映延迟。

  • 实际上,你会发现该指标与真实延迟数值不符:数据明显差异时显示 0 或出现与复制性能无关的峰值。

这种现象的根源在于该值的计算方法和 MySQL 5.7 的复制架构设计。让我们结合源码剖析一下。

根源一:计算方法的局限性

Seconds_Behind_Master 的计算逻辑定义在 MySQL 5.7 的代码中:

longlong slave_seconds_behind_master(Master_info* mi){  longlong t0 = mi->clock_diff_with_master;  longlong t1 = mi->rli->last_master_timestamp;  longlong t2 = mi->get_master_log_pos() ? time(NULL) : 0;  return (t2 > t1) ? (t2 - t1 - t0) : 0;           }

变量说明

  • t0(clock_diff_with_master):校正主从时钟偏差。

  • t1(last_master_timestamp):主库二进制日志事件的时间戳。

  • t2(time(NULL)):从库当前时间(源码中实际使用 POSIX 时间函数)。

  • 返回值为秒,源码中直接返回时间差,未除以 1000000。

问题点

该计算假定 t1 是事件在主库执行的时间,但实际上它是事件写入二进制日志的时间,受事务提交顺序和 sync_binlog 配置影响。例如,若 sync_binlog=0,日志写入可能滞后,导致 t1 与实际执行时间脱节。

根源二:单线程 SQL 线程的延迟掩盖

MySQL 5.7 默认使用单线程 SQL 线程应用事件,时间戳更新逻辑在代码中:

void Relay_log_info::set_master_log_pos(ulonglong pos){  // 简化表示,实际更复杂  if (pos)    last_master_timestamp = log_pos_to_timestamp(pos); }

问题点

若一个大事务(如批量 UPDATE)在从库执行耗时 10 秒,last_master_timestamp 仅在事务完成时更新。在此期间,Seconds_Behind_Master 不变,完成后才跳至 10,无法实时反映延迟。这正是我们生产环境中大事务导致延迟的关键原因。

根源三:并行复制的误报

MySQL 5.7 支持多线程复制(slave_parallel_workers),但 Seconds_Behind_Master 未有效处理并行执行:

if (mi->rli->slave_parallel_workers > 0 && mi->rli->last_master_timestamp)  return time(NULL) - mi->rli->last_master_timestamp;

问题点

该值仅基于最后应用的事件时间戳,未聚合各线程的延迟。若一个线程因大事务滞后,其他线程已同步,指标仍可能显示 0,掩盖真实延迟。

根源四:网络和 I/O 延迟的忽略

问题点

Seconds_Behind_Master 不反映 I/O 线程从主库拉取事件或写入中继日志的延迟。若网络问题导致 I/O 线程落后,但 SQL 线程已处理完中继日志,指标仍误报 0。

小结

Seconds_Behind_Master 因依赖不准确的事件时间戳、缺乏实时更新、无法反映并行复制和 I/O 延迟,成为一个不可靠的指标。面对业务需求,它无法提供精确的延迟时间。

MySQL 5.7 的 Seconds_Behind_Master 并不可靠!

3解决方案:pt-heartbeat

如何获取主从延迟时间值?

pt-heartbeat[3] 是 Percona Toolkit 中的工具,通过在主库注入心跳记录并在从库比较时间戳,提供精确的延迟测量。

来源:https://docs.percona.com/percona-toolkit/pt-heartbeat.html

操作步骤如下:

主库:运行更新心跳表。

-- 主库创建表 heartbeat.heartbeat,包含 ts(时间戳)和 server_id-- 每秒更新一行记录 --interval=1pt-heartbeat --user=root --password=xxx --create-table --update --interval=1 -D heartbeat

从库:监控或检查延迟。

--  输出实时延迟,如 0.02spt-heartbeat --user=root --password=xxx --monitor -D heartbeat

如何判断获取的值是准确的?

从 pt-heartbeat 的 Perl 源码分析其原理:

心跳注入代码块

sub update_heartbeat {  my ($dbh) = @_;  my $ts = $dbh->selectrow_array('SELECT NOW(6)'); 主库当前时间  my $server_id = $dbh->selectrow_array('SELECT @@server_id');  $dbh->do("INSERT INTO heartbeat.heartbeat (id, ts, server_id) VALUES (1, ?, ?) "         . "ON DUPLICATE KEY UPDATE ts = ?, server_id = ?", undef, $ts, $server_id, $ts, $server_id);}

延迟计算代码块

sub check_heartbeat {  my ($dbh) = @_;  my $row = $dbh->selectrow_hashref("SELECT ts FROM heartbeat.heartbeat WHERE id = 1");  my $master_ts = $row->{ts};        主库时间戳  my $slave_ts = $dbh->selectrow_array('SELECT NOW(6)'); 从库当前时间  my $lag = time_diff($slave_ts, $master_ts); 计算延迟  return sprintf("%.2f", $lag);}

准确性分析:

  • 实时性:心跳记录每秒更新,延迟反映记录从主库写入到从库应用的时间,精确到微秒。

  • 独立性:不依赖 MySQL 复制线程的时间戳,避免了 Seconds_Behind_Master 的缺陷。

  • 局限性:需确保主从时钟同步,否则需用 --skew 调整。

4结论与建议

在 MySQL 5.7 中,Seconds_Behind_Master 因设计缺陷无法满足业务对精确延迟的需求。源码分析揭示其依赖不准确的时间戳和缺乏实时性,尤其在大事务场景下表现不佳。

相比之下,pt-heartbeat 通过心跳机制提供实时、精确的延迟测量,是解决此类问题的理想工具。

建议

  • 在生产环境部署 pt-heartbeat,设置合理的 --interval(如 0.5 秒)以平衡精度和负载。

  • 配置主从时钟同步(如 NTP),确保延迟值可靠。

  • 结合业务需求,设置延迟阈值告警,优化大事务处理。

  • 通过这一方案,我们不仅满足了业务需求,还提升了复制监控的可靠性,为系统稳定性提供了保障。

    参考资料

    [1]

    eol-notice: https://www.mysql.com/support/eol-notice.html

    [2]

    show-slave-status: https://dev.mysql.com/doc/refman/5.7/en/show-slave-status.html

    [3]

    pt-heartbeat: https://docs.percona.com/percona-toolkit/pt-heartbeat.html

    图片

      推荐阅读:

  • Mysql 是什么?架构是怎么样的?

  • MySQL 索引失效了吧

  • 一个 MySQL 隐式转换的坑,差点把服务器搞挂了

  • 糟了,数据库崩了,又好像没蹦

  • 数据库死锁排查思路分享

  • (0)
    wd123_cnwd123_cn
    上一篇 2025年3月23日 上午10:21
    下一篇 2025年3月23日 上午10:22

    相关文章

    • 狗狗乘车指南:如何识别焦虑信号并提供舒适旅程

      许多爱狗人士都喜欢带着他们的毛茸茸的朋友一起旅行,但汽车旅行对狗狗来说可能并不总是愉快的。即使您尽力让它们感到舒适,带上它们最喜欢的玩具,您的狗狗也可能经历焦虑和晕车等问题。英国汽车租赁公司Select Car Leasing与认证犬类行为学家Caroline Wilkinson(Barket Place创始人)和专业宠物出租车服务Pets 2 Place创…

      2025年3月25日
    • 感人瞬间:女儿赠送演唱会门票,母亲感动落泪

      有时,妈妈们最想要的只是与孩子们共度时光。Lindy Dunne在她的TikTok视频中捕捉到了这种感觉,视频中她送给母亲George Strait和Chris Stapleton的演唱会门票作为惊喜。 母亲的慷慨与无私 Dunne告诉《人物》杂志,Magliazzo对与家人共度时光的反应准确体现了她的性格:以家庭为中心,心地善良,待人友善。”她照顾我的孩子…

      2025年3月10日
    • 研究表明:过度使用ChatGPT或加剧孤独感

      自从OpenAI发布ChatGPT以来,这款人工智能聊天机器人迅速风靡全球,目前每周活跃用户已达4亿。然而,一项最新研究表明,在提高工作效率的同时,过度使用ChatGPT可能反而会加剧用户的孤独感。 OpenAI与MIT联合研究揭示潜在风险 OpenAI和麻省理工学院媒体实验室(MIT Media Lab)联合发布了一份研究报告,分析了数百万条聊天记录和数千…

      2025年3月25日
    • ESPN体育评论员迪克·维塔莱分享抗癌心路历程:保持积极,永不放弃

      知名体育评论员、ESPN资深解说员迪克·维塔莱(Dick Vitale)近日公开分享了他的抗癌经历,并向所有正在与癌症作斗争的人们传递了充满力量和希望的信息。 维塔莱的抗癌历程 2024年6月,维塔莱在社交媒体平台X上宣布,他在颈部淋巴结中发现了新的癌细胞,需要接受治疗。这一消息牵动了无数粉丝的心。 “我的颈部淋巴结活检报告出来了,结果显示是癌性的,”他写道…

      2025年3月17日
    • 比亚迪市值七年来首次超过宁德时代

      来源 | 潇湘晨报 记者 | 胡雄 动力电池第二的比亚迪实现对动力电池“宁王”宁德时代的市值反超。截至3月17日收盘,比亚迪股价上涨1.15%,报380.25元,市值达到1.16万亿元。同期,宁德时代股价下跌2.29%,报256元,市值为1.13万亿元。 3月18日开盘,比亚迪依然对宁德时代保持领先,比亚迪股价上涨1.99%,报387.80元,市值达到1.1…

      2025年3月19日
    • NFL自由球员市场开启:大牌球员动向与球队策略分析

      NFL的自由球员合法接触窗口于周一正式开启,随之而来的是一系列交易和续约活动。尽管自由球员的正式签约窗口要到周三才开启,但球队们已经迫不及待地开始了各种操作。从四分卫到外接手,再到年度最佳防守球员,球队们在自由市场中的动作已经引发了球迷的广泛关注。 赢家 汤姆·布雷迪: 作为福克斯的解说员,布雷迪在解说比赛中对四分卫的表现进行了严厉的点评。作为拉斯维加斯突袭…

      2025年3月11日