详解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 相关文章推荐
linux下导入、导出mysql数据库命令的实现方法
May 26 MySQL
修改MySQL的默认密码的四种小方法
May 26 MySQL
浅谈MySQL next-key lock 加锁范围
Jun 07 MySQL
安装配置mysql及Navicat prenium的详细流程
Jun 10 MySQL
使用ORM新增数据在Mysql中的操作步骤
Jul 26 MySQL
彻底解决MySQL使用中文乱码的方法
Jan 22 MySQL
Mysql事务索引知识汇总
Mar 17 MySQL
MySQL分区表管理命令汇总
Mar 21 MySQL
一次Mysql update sql不当引起的生产故障记录
Apr 01 MySQL
MySQL表锁、行锁、排它锁及共享锁的使用详解
Apr 02 MySQL
MySQL优化之慢日志查询
Jun 10 MySQL
mysql函数之截取字符串的实现
Aug 14 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
JS与PHP向函数传递可变参数的区别实例代码
2011/05/18 PHP
php创建session的方法实例详解
2015/01/27 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
yii框架使用分页的方法分析
2019/07/25 PHP
Thinkphp框架使用list_to_tree 实现无限级分类列出所有节点示例
2020/04/04 PHP
JS/jQuery实现默认显示部分文字点击按钮显示全部内容
2013/05/13 Javascript
js内存泄露的几种情况详细探讨
2013/05/31 Javascript
jQuery之ajax技术的详细介绍
2013/06/19 Javascript
JavaScript判断用户是否对表单进行了修改的方法
2015/03/18 Javascript
纯JS代码实现一键分享功能
2016/04/20 Javascript
Angular.js中angular-ui-router的简单实践
2017/07/18 Javascript
JavaScript去掉数组重复项的方法分析【测试可用】
2018/07/19 Javascript
jQuery使用bind动态绑定事件无效的处理方法
2018/12/11 jQuery
页面内锚点定位及跳转方法总结(推荐)
2019/04/24 Javascript
前端js中的事件循环eventloop机制详解
2019/05/15 Javascript
手把手带你入门微信小程序新框架Kbone的使用
2020/02/25 Javascript
Python2.x中str与unicode相关问题的解决方法
2015/03/30 Python
Pycharm学习教程(5) Python快捷键相关设置
2017/05/03 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
python自动截取需要区域,进行图像识别的方法
2018/05/17 Python
python 3调用百度OCR API实现剪贴板文字识别
2018/09/04 Python
Python 中Django安装和使用教程详解
2019/07/03 Python
自定义django admin model表单提交的例子
2019/08/23 Python
Python3 翻转二叉树的实现
2019/09/30 Python
PyCharm取消波浪线、下划线和中划线的实现
2020/03/03 Python
python中关于数据类型的学习笔记
2020/07/19 Python
Expedia丹麦:全球领先的旅游网站
2018/03/18 全球购物
美国战术品牌:5.11 Tactical
2019/05/01 全球购物
出纳工作岗位责任制
2014/02/02 职场文书
老师的检讨书
2014/02/23 职场文书
邓小平理论心得体会
2014/09/09 职场文书
民主生活会剖析材料
2014/09/30 职场文书
科技活动总结范文
2015/05/11 职场文书
迁徙的鸟观后感
2015/06/09 职场文书