详解MySQL的Seconds_Behind_Master


Posted in MySQL onMay 18, 2021

Seconds_Behind_Master

对于mysql主备实例,seconds_behind_master是衡量master与slave之间延时的一个重要参数。通过在slave上执行"show slave status;"可以获取seconds_behind_master的值。

原始实现

Definition:The number of seconds that the slave SQL thread is behind processing the master binary log.

Type:time_t(long)

计算方式如下:

rpl_slave.cc::show_slave_status_send_data()
if ((mi->get_master_log_pos() == mi->rli->get_group_master_log_pos()) &&
       (!strcmp(mi->get_master_log_name(),
                mi->rli->get_group_master_log_name()))) {
     if (mi->slave_running == MYSQL_SLAVE_RUN_CONNECT)
       protocol->store(0LL);
     else
       protocol->store_null();
   } else {
     long time_diff = ((long)(time(0) - mi->rli->last_master_timestamp) -
                       mi->clock_diff_with_master);
     protocol->store(
         (longlong)(mi->rli->last_master_timestamp ? max(0L, time_diff) : 0));
   }

主要分为以下两种情况:

  • SQL线程等待IO线程获取主机binlog,此时seconds_behind_master为0,表示备机与主机之间无延时;
  • SQL线程处理relay log,此时seconds_behind_master通过(long)(time(0) ? mi->rli->last_master_timestamp) ? mi->clock_diff_with_master计算得到;

last_master_timestamp

定义:

主库binlog中事件的时间。

type: time_t (long)

计算方式:

last_master_timestamp根据备机是否并行复制有不同的计算方式。

非并行复制:

rpl_slave.cc:exec_relay_log_event()
if ((!rli->is_parallel_exec() || rli->last_master_timestamp == 0) &&
    !(ev->is_artificial_event() || ev->is_relay_log_event() ||
     (ev->common_header->when.tv_sec == 0) ||
     ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT ||
     ev->server_id == 0))
{
 rli->last_master_timestamp= ev->common_header->when.tv_sec +
                             (time_t) ev->exec_time;
 DBUG_ASSERT(rli->last_master_timestamp >= 0);
}

在该模式下,last_master_timestamp表示为每一个event的结束时间,其中when.tv_sec表示event的开始时间,exec_time表示事务的执行时间。该值的计算在apply_event之前,所以event还未执行时,last_master_timestamp已经被更新。由于exec_time仅在Query_log_event中存在,所以last_master_timestamp在应用一个事务的不同event阶段变化。以一个包含两条insert语句的事务为例,在该代码段的调用时,打印出event的类型、时间戳和执行时间

create table t1(a int PRIMARY KEY AUTO_INCREMENT ,b longblob) engine=innodb;
begin;
insert into t1(b) select repeat('a',104857600);
insert into t1(b) select repeat('a',104857600);
commit;

10T06:41:32.628554Z 11 [Note] [MY-000000] [Repl] event_type: 33 GTID_LOG_EVENT

2020-02-10T06:41:32.628601Z 11 [Note] [MY-000000] [Repl] event_time: 1581316890

2020-02-10T06:41:32.628614Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

2020-02-10T06:41:32.628692Z 11 [Note] [MY-000000] [Repl] event_type: 2   QUERY_EVENT

2020-02-10T06:41:32.628704Z 11 [Note] [MY-000000] [Repl] event_time: 1581316823

2020-02-10T06:41:32.628713Z 11 [Note] [MY-000000] [Repl] event_exec_time: 35

2020-02-10T06:41:32.629037Z 11 [Note] [MY-000000] [Repl] event_type: 19   TABLE_MAP_EVENT

2020-02-10T06:41:32.629057Z 11 [Note] [MY-000000] [Repl] event_time: 1581316823

2020-02-10T06:41:32.629063Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

2020-02-10T06:41:33.644111Z 11 [Note] [MY-000000] [Repl] event_type: 30    WRITE_ROWS_EVENT

2020-02-10T06:41:33.644149Z 11 [Note] [MY-000000] [Repl] event_time: 1581316823

2020-02-10T06:41:33.644156Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

2020-02-10T06:41:43.520272Z 0 [Note] [MY-011953] [InnoDB] Page cleaner took 9185ms to flush 3 and evict 0 pages

2020-02-10T06:42:05.982458Z 11 [Note] [MY-000000] [Repl] event_type: 19   TABLE_MAP_EVENT

2020-02-10T06:42:05.982488Z 11 [Note] [MY-000000] [Repl] event_time: 1581316858

2020-02-10T06:42:05.982495Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

2020-02-10T06:42:06.569345Z 11 [Note] [MY-000000] [Repl] event_type: 30    WRITE_ROWS_EVENT

2020-02-10T06:42:06.569376Z 11 [Note] [MY-000000] [Repl] event_time: 1581316858

2020-02-10T06:42:06.569384Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

2020-02-10T06:42:16.506176Z 0 [Note] [MY-011953] [InnoDB] Page cleaner took 9352ms to flush 8 and evict 0 pages

2020-02-10T06:42:37.202507Z 11 [Note] [MY-000000] [Repl] event_type: 16    XID_EVENT

2020-02-10T06:42:37.202539Z 11 [Note] [MY-000000] [Repl] event_time: 1581316890

2020-02-10T06:42:37.202546Z 11 [Note] [MY-000000] [Repl] event_exec_time: 0

并行复制:

rpl_slave.cc   mts_checkpoint_routine
ts = rli->gaq->empty()
          ? 0
          : reinterpret_cast<Slave_job_group *>(rli->gaq->head_queue())->ts;
 rli->reset_notified_checkpoint(cnt, ts, true);
 /* end-of "Coordinator::"commit_positions" */

在该模式下备机上存在一个分发队列gaq,如果gaq为空,则设置last_commit_timestamp为0;如果gaq不为空,则此时维护一个checkpoint点lwm,lwm之前的事务全部在备机上执行完成,此时last_commit_timestamp被更新为lwm所在事务执行完成后的时间。该时间类型为time_t类型。

ptr_group->ts = common_header->when.tv_sec +
                   (time_t)exec_time;  // Seconds_behind_master related
rli->rli_checkpoint_seqno++;
if (update_timestamp) {
 mysql_mutex_lock(&data_lock);
 last_master_timestamp = new_ts;
 mysql_mutex_unlock(&data_lock);
}

在并行复制下,event执行完成之后才会更新last_master_timestamp,所以非并行复制和并行复制下的seconds_behind_master会存在差异。

clock_diff_with_master

定义:

  • The difference in seconds between the clock of the master and the clock of the slave (second - first). It must be signed as it may be <0 or >0. clock_diff_with_master is computed when the I/O thread starts; for this the I/O thread does a SELECT UNIX_TIMESTAMP() on the master.
  • type: long
rpl_slave.cc::get_master_version_and_clock()
if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) &&
     (master_res= mysql_store_result(mysql)) &&
     (master_row= mysql_fetch_row(master_res)))
 {
   mysql_mutex_lock(&mi->data_lock);
   mi->clock_diff_with_master=
     (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));
   DBUG_EXECUTE_IF("dbug.mts.force_clock_diff_eq_0",
     mi->clock_diff_with_master= 0;);
   mysql_mutex_unlock(&mi->data_lock);
 }

该差值仅被计算一次,在master与slave建立联系时处理。

其他

exec_time

定义:

  • the difference from the statement's original start timestamp and the time at which it completed executing.
  • type: unsigned long
struct timeval end_time;
ulonglong micro_end_time = my_micro_time();
my_micro_time_to_timeval(micro_end_time, &end_time);
exec_time = end_time.tv_sec - thd_arg->query_start_in_secs();

时间函数

(1)time_t time(time_t timer) time_t为long类型,返回的数值仅精确到秒;

(2)int gettimeofday (struct timeval *tv, struct timezone *tz) 可以获得微秒级的当前时间;

(3)timeval结构

#include <time.h>
stuct timeval {
   time_t tv_sec; /*seconds*/
   suseconds_t tv_usec; /*microseconds*/
}

总结

使用seconds_behind_master衡量主备延时只能精确到秒级别,且在某些场景下,seconds_behind_master并不能准确反映主备之间的延时。主备异常时,可以结合seconds_behind_master源码进行具体分析。

以上就是详解MySQL的Seconds_Behind_Master的详细内容,更多关于MySQL Seconds_Behind_Master的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
mysql批量新增和存储的方法实例
Apr 07 MySQL
MySQL sql_mode的使用详解
May 08 MySQL
如何用Navicat操作MySQL
May 12 MySQL
详解Mysql和Oracle之间的误区
May 18 MySQL
IDEA 链接Mysql数据库并执行查询操作的完整代码
May 20 MySQL
一看就懂的MySQL的聚簇索引及聚簇索引是如何长高的
May 25 MySQL
修改MySQL的数据库引擎为INNODB的方法
May 26 MySQL
MySQL Router实现MySQL的读写分离的方法
May 27 MySQL
MySQL 外键约束和表关系相关总结
Jun 20 MySQL
weblogic服务建立数据源连接测试更新mysql驱动包的问题及解决方法
Jan 22 MySQL
简单聊一聊SQL注入及防止SQL注入
Mar 23 MySQL
分享很少见很有用的SQL功能CORRESPONDING
Aug 05 MySQL
MySQL优化之如何写出高质量sql语句
May 17 #MySQL
mysql数据库入门第一步之创建表
MySQL 隔离数据列和前缀索引的使用总结
May 14 #MySQL
MySQL 使用自定义变量进行查询优化
May 14 #MySQL
MySQL 逻辑备份与恢复测试的相关总结
May 14 #MySQL
MySQL 可扩展设计的基本原则
May 14 #MySQL
MySQL主从搭建(多主一从)的实现思路与步骤
May 13 #MySQL
You might like
计数器详细设计
2006/10/09 PHP
thinkPHP中session()方法用法详解
2016/12/08 PHP
PHP实现的简单sha1加密功能示例
2017/08/27 PHP
PHP论坛实现积分系统的思路代码详解
2020/06/01 PHP
js验证表单大全
2006/11/25 Javascript
JS 面向对象的5钟写法
2009/07/31 Javascript
利用jQuery简单实现产品展示图片左右滚动功能(示例代码)
2014/01/02 Javascript
jQuery中parentsUntil()方法用法实例
2015/01/07 Javascript
node.js cookie-parser之parser.js
2016/06/06 Javascript
jQuery实现微信长按识别二维码功能
2016/08/26 Javascript
基于JS+Canves实现点击按钮水波纹效果
2016/09/15 Javascript
详解Vue2.0里过滤器容易踩到的坑
2017/06/01 Javascript
javascript自定义事件功能与用法实例分析
2017/11/08 Javascript
微信小程序实现搜索功能并跳转搜索结果页面
2019/05/18 Javascript
JS设置自定义快捷键并实现图片上下左右移动
2019/10/17 Javascript
[02:46]解说DC:感谢430陪伴我们的DOTA2国际邀请赛岁月
2016/06/29 DOTA
[58:37]Serenity vs Fnatic 2018国际邀请赛淘汰赛BO1 8.21
2018/08/22 DOTA
python实现在pickling的时候压缩的方法
2014/09/25 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
python自定义时钟类、定时任务类
2021/02/22 Python
Python接口测试get请求过程详解
2020/02/28 Python
在jupyter notebook 添加 conda 环境的操作详解
2020/04/10 Python
30行Python代码实现高分辨率图像导航的方法
2020/05/22 Python
python实现三种随机请求头方式
2021/01/05 Python
HTML5 本地存储 LocalStorage详解
2016/06/24 HTML / CSS
迪斯尼假期(欧洲、中东及非洲):Disney Holidays EMEA
2021/02/15 全球购物
C#面试问题
2016/07/29 面试题
Java Servlet的主要功能和作用是什么
2014/02/14 面试题
中学生学习生活的自我评价
2013/10/26 职场文书
小学生操行评语大全
2014/04/22 职场文书
文化产业实施方案
2014/06/07 职场文书
初中同学会活动方案
2014/08/22 职场文书
汶川大地震感悟
2015/08/10 职场文书
PostGIS的安装与入门使用指南
2022/01/18 PostgreSQL
微信小程序APP的事件绑定以及传递参数时的冒泡和捕获
2022/04/19 Javascript
Python编写车票订购系统 Python实现快递收费系统
2022/08/14 Python