Seconds_Behind_Master计算原理

当从库上复制IO进程和复制SQL进程正常运行,且SQL线程处于执行状态而非等待IO进程同步BINLOG时,复制延迟时间计算如下:

复制延迟时间(Seconds_Behind_Master)  =  当前从库系统时间(time()) - 最后binlog的时间戳( mi->rli->last_master_timestamp) - 主从系统时间差(mi->clock_diff_with_master)

最后binlog的时间戳( mi->rli->last_master_timestamp)  =  最后binlog事件开始时间(ev->when.tv_sec)+最后binlog事件执行时间((time_t) ev->exec_time)
主从系统时间差(mi->clock_diff_with_master) = 从库系统时间(time((time_t*) 0)) - 主库系统时间(UNIX_TIMESTAMP())

上面变量中,从库系统时间和主库系统时间都是相对稳定的值,因此主从系统时间差相对稳定,在复制IO进程启动时计算,因此影响复制延迟的主要因素有:

1、当前从库系统时间(time(0)),当前从库系统时间会随时间推移而增长变化,尤其在处理超大事务或超大表DDL变更操作时尤为明显。

2、最后binlog事件开始时间(ev->when.tv_sec),当一个BINLOG事件被写入到BINLOG文件时,该BINLOG事件的开始时间便已确定,但并行复制和非并行复制两种复制模式更新“最后binlog的时间戳”存在差异。

3、最后binlog事件执行时间((time_t) ev->exec_time),当一个BINLOG事件被写入到BINLOG文件时,该BINLOG事件的执行时间也已确定,但行格式和语句格式两种复制格式会导致时间中记录的exec_time存在差异。

非并行复制模式下last_master_timestamp更新

当SQL线程从relay log中读取到binlog event后,会先更新last_master_timestamp,再应用binlog event。

当SQL线程应用完relay log中所有binlog event并处以等待状态时,会更新last_master_timestamp为0,且复制延迟时间(Seconds_Behind_Master)被赋值为0。

并行复制模式下last_master_timestamp更新

并行复制模式下,会创建一个分发队列GAP来协调多个SQL进程消费不同binlog evenet,并根据条件(参数slave_checkpoint_group,默认512个事务)或定期(参数slave_checkpoint_period,默认300ms)触发一个checkpoint来推进当前从库执行事务的最低水位线LWM(low-warter mark)。如队列中有1-8号事务,而1、2、3、4、6、7号事务已被执行,剩余5和8号事务正在执行或等待执行,则已执行事务的最低水位线为4。

当执行GAP Checkpoint更新LWM时,会同时更新last_master_timestamp为LWM所在事务结束的EVENT时间,而由于LWM所在事务已被执行,因此是先应用binlog event再更新last_master_timestamp。

由于并行复制模式下不是在BINLOG EVENT执行完成后实时更新last_master_timestamp,因此会导致last_master_timestamp存在误差,在没有延迟情况下仍显示轻微延迟(slave_checkpoint_period + 事务在备库执行时间)。

并行复制参数介绍:

slave_checkpoint_period,default 300
Sets the maximum time (in milliseconds) that is allowed to pass before a checkpoint operation is called to update the status of a multithreaded slave as shown by SHOW SLAVE STATUS. Setting this variable has no effect on slaves for which multithreading is not enabled. Setting this variable takes effect for all replication channels immediately, including running channels. slave_checkpoint_group,default 512
Sets the maximum number of transactions that can be processed by a multithreaded slave before a checkpoint operation is called to update its status as shown by SHOW SLAVE STATUS. Setting this variable has no effect on slaves for which multithreading is not enabled. Setting this variable has no immediate effect. The state of the variable applies on all subsequent START SLAVE commands.

复制格式(BINLOG_FORMAT)对exec_time的影响

在测试环境上执行下面语句:

begin;
select now();
update tb003 set c1=sleep(5) where id=1;
select sleep(3);
select now();
update tb003 set c1=sleep(10) where id=2;
commit;

基于BINLOG_FORMAT=STATEMENT复制格式的BINLOG解析如下:

# at 14681
#190625 23:18:14 server id 1614520 end_log_pos 14746 CRC32 0xdc27cdef GTID last_committed=48 sequence_number=49 rbr_only=no
SET @@SESSION.GTID_NEXT= '025fd638-89ea-11e9-a749-40f2e9cf3aaa:112'/*!*/;
# at 14746
#190625 23:17:56 server id 1614520 end_log_pos 14827 CRC32 0xf931e3c0 Query thread_id=3837 exec_time=5 error_code=0
SET TIMESTAMP=1561475876/*!*/;BEGIN
/*!*/;
# at 14827
#190625 23:17:56 server id 1614520 end_log_pos 14942 CRC32 0x3bc48f78 Query thread_id=3837 exec_time=5 error_code=0
use `db001`/*!*/;
SET TIMESTAMP=1561475876/*!*/;
update tb003 set c1=sleep(5) where id=1
/*!*/;
# at 14942
#190625 23:18:04 server id 1614520 end_log_pos 15058 CRC32 0x053d4b3c Query thread_id=3837 exec_time=10 error_code=0
SET TIMESTAMP=1561475884/*!*/;
update tb003 set c1=sleep(10) where id=2
/*!*/;
# at 15058
#190625 23:18:14 server id 1614520 end_log_pos 15089 CRC32 0x5e7dfecd Xid = 11788
COMMIT/*!*/;

基于BINLOG_FORMAT=ROW复制格式的BINLOG解析如下:

# at 15375
#190625 23:24:46 server id 1614520 end_log_pos 15440 CRC32 0x0efa5343 GTID last_committed=50 sequence_number=51 rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '025fd638-89ea-11e9-a749-40f2e9cf3aaa:114'/*!*/;
# at 15440
#190625 23:24:28 server id 1614520 end_log_pos 15513 CRC32 0x2b522fd6 Query thread_id=3837 exec_time=5 error_code=0
SET TIMESTAMP=1561476268/*!*/;
BEGIN
/*!*/;
# at 15513
#190625 23:24:28 server id 1614520 end_log_pos 15576 CRC32 0x3753fee7 Rows_query
# update tb003 set c1=sleep(5) where id=1
# at 15576
#190625 23:24:28 server id 1614520 end_log_pos 15628 CRC32 0xd8ef6183 Table_map: `db001`.`tb003` mapped to number 229
# at 15628
#190625 23:24:28 server id 1614520 end_log_pos 15698 CRC32 0x70dcd9f1 Update_rows: table id 229 flags: STMT_END_F ### UPDATE `db001`.`tb003`
### WHERE
### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=1 /* INT meta=0 nullable=1 is_null=0 */
### @3=1561476236 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### SET
### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=0 /* INT meta=0 nullable=1 is_null=0 */
### @3=1561476268 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
# at 15698
#190625 23:24:36 server id 1614520 end_log_pos 15762 CRC32 0x64123971 Rows_query
# update tb003 set c1=sleep(10) where id=2
# at 15762
#190625 23:24:36 server id 1614520 end_log_pos 15814 CRC32 0xfb3c7742 Table_map: `db001`.`tb003` mapped to number 229
# at 15814
#190625 23:24:36 server id 1614520 end_log_pos 15884 CRC32 0xbd3dacd0 Update_rows: table id 229 flags: STMT_END_F ### UPDATE `db001`.`tb003`
### WHERE
### @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=1 /* INT meta=0 nullable=1 is_null=0 */
### @3=1561476236 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
### SET
### @1=2 /* LONGINT meta=0 nullable=0 is_null=0 */
### @2=0 /* INT meta=0 nullable=1 is_null=0 */
### @3=1561476276 /* TIMESTAMP(0) meta=0 nullable=0 is_null=0 */
# at 15884
#190625 23:24:46 server id 1614520 end_log_pos 15915 CRC32 0x4d2dba05 Xid = 11799
COMMIT/*!*/;

从上面的解析结果可以得出:

1、在BEGIN语句开始前的exec_time是事务中第一条语句的执行时间,而非整个事务的执行时间。

2、在ROW复制格式下,exec_time值仅存在事务开始前(BEGIN语句前),在整个事务中没有记录单个语句操作的执行时间。

3、在STATEMENT复制格式下,事务开始前(BEGIN语句前)的包含事务中第一条语句的执行时间,在整个事务中单个语句操作前也包含该语句的执行时间。

4、在事务提交操作前(COMMIT)包含有事务的开始时间和xid,并不包含整个事务的执行时间。

非并行复制模式+STATEMENT复制格式下的复制延迟

测试环境:

MySQL 版本:MySQL 5.7.

主库设置:
binlog_format = 'STATEMENT' 从库设置:
binlog_format = 'STATEMENT'
slave_parallel_type='DATABASE' 主库系统时间和从库系统时间完全不同,不存在时间差。

主库执行:

update tb003 set c1=sleep() where id=;

复制复制延迟情况如下:

--xx xx:xx:xx  从库IO线程同步,获取主库系统时间,主从时间同步,主从系统时间差(mi->clock_diff_with_master)=0秒
-- :: 主库开始执行SQL(ev->when.tv_sec="2019-06-24 20:13:20"),主从同步,从库复制延迟0秒
-- :: 主库执行SQL完成,执行时间5秒(ev->exec_time=5秒),从库SQL线程等待IO线程获取BINLOG EVENT,从库复制延迟0秒
-- :: 主库将BINLOG推送给从库,从库SQL线程等待IO线程获取BINLOG EVENT,从库复制延迟0秒
-- :: 从库IO线程接受到BINLOG EVENT并保存到RELAY LOG中,从库SQL线程等待IO线程获取BINLOG EVENT,从库复制延迟0秒
-- :: 从库SQL线程读取到RELAY LOG中的BINLOG EVENT,并更新last_master_timestamp,复制延迟0秒。
从库复制延迟时间计算如下:
最后binlog的时间戳( mi->rli->last_master_timestamp) = 最后binlog事件开始时间(ev->when.tv_sec)+最后binlog事件执行时间((time_t) ev->exec_time)
= "2019-06-24 20:13:20" + "5秒"
= "2019-06-24 20:13:25"
复制延迟时间(Seconds_Behind_Master) = 当前从库系统时间(time()) - 最后binlog的时间戳( mi->rli->last_master_timestamp) - 主从系统时间差(mi->clock_diff_with_master)
= "2019-06-24 20:13:25" - "2019-06-24 20:13:25" - "0秒"
= 0秒 -- :: 从库上last_master_timestamp和clock_diff_with_master都未发生变化,从库时间增加1秒,主从复制延迟为1秒
-- :: 从库上last_master_timestamp和clock_diff_with_master都未发生变化,从库时间增加1秒,主从复制延迟为2秒
......
-- :: 从库上last_master_timestamp和clock_diff_with_master都未发生变化,从库时间增加1秒,主从复制延迟为5秒
-- :: 从库执行到事务的最后COMMIT EVENT,由于该EVENT无exec_time(ev->exec_time=0秒),更新last_master_timestamp,复制延迟11秒。
从库复制延迟时间计算如下:
最后binlog的时间戳( mi->rli->last_master_timestamp) = 最后binlog事件开始时间(ev->when.tv_sec)+最后binlog事件执行时间((time_t) ev->exec_time)
= "2019-06-24 20:13:20" + "0秒"
= "2019-06-24 20:13:20"
复制延迟时间(Seconds_Behind_Master) = 当前从库系统时间(time()) - 最后binlog的时间戳( mi->rli->last_master_timestamp) - 主从系统时间差(mi->clock_diff_with_master)
= "2019-06-24 20:13:31" - "2019-06-24 20:13:20" - "0秒"
= 11秒 -- :: 从库SQL线程应用完RELAY LOG中的所有BINLOG EVENT,SQL线程进入等待状态,last_master_timestamp被更新为0,从库复制延迟0秒。

从库延迟11秒的时间很短,需要刷新频率高(每0.1秒扫描一次)的情况下才能发现。

并行复制模式+STATEMENT复制格式下的复制延迟

测试环境:

MySQL 版本:MySQL 5.7.19

主库设置:
binlog_format = 'STATEMENT' 从库设置:
binlog_format = 'STATEMENT'
slave_parallel_type='LOGICAL_CLOCK'
slave_parallel_workers = 8
slave_preserve_commit_order = ON 主库系统时间和从库系统时间完全不同,不存在时间差。

主库上执行:

## 执行周期 2019-06-26 09:32:53-- 2019-06-26 09:33:03,执行时间10秒
update tb003 set c1=SLEEP(10) where id=1;
## 执行周期 2019-06-26 09:33:03-- 2019-06-26 09:33:13,执行时间10秒
update tb003 set c1=SLEEP(10) where id=2;
## 执行周期 2019-06-26 09:33:13-- 2019-06-26 09:33:23,执行时间10秒
update tb003 set c1=SLEEP(10) where id=3;

从库上复制延迟:

## 从库上Relay_Master_Log_File未发送变化,因此只描述Exec_Master_Log_Pos变化
2019-06-26 09:32:53之前 Exec_Master_Log_Pos=18287,Seconds_Behind_Master=0
2019-06-26 09:32:53 -- 2019-06-26 09:33:13 Exec_Master_Log_Pos=18287,Seconds_Behind_Master=0
2019-06-26 09:33:14 -- 2019-06-26 09:33:23 Exec_Master_Log_Pos=18631,Seconds_Behind_Master 从10增长到19
2019-06-26 09:33:24 -- 2019-06-26 09:33:33 Exec_Master_Log_Pos=18975,Seconds_Behind_Master 从10增长到19
2019-06-26 09:33:34之后 Exec_Master_Log_Pos=19319,Seconds_Behind_Master=0

主库BINLOG解析结果为:

# at 18287
#190626 9:32:53 server id 1614520 end_log_pos 18352 CRC32 0x9bfcc652 GTID last_committed=59 sequence_number=60 rbr_only=no
SET @@SESSION.GTID_NEXT= '025fd638-89ea-11e9-a749-40f2e9cf3aaa:123'/*!*/;
# at 18352
#190626 9:32:53 server id 1614520 end_log_pos 18433 CRC32 0x0244bb1a Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512773/*!*/;
BEGIN
/*!*/;
# at 18433
#190626 9:32:53 server id 1614520 end_log_pos 18549 CRC32 0xea35ba85 Query thread_id=3848 exec_time=10 error_code=0
use `db001`/*!*/;
SET TIMESTAMP=1561512773/*!*/;
update tb003 set c1=SLEEP(10) where id=1
/*!*/;
# at 18549
#190626 9:32:53 server id 1614520 end_log_pos 18631 CRC32 0x0aafadd6 Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512773/*!*/;
COMMIT
/*!*/;
# at 18631
#190626 9:33:03 server id 1614520 end_log_pos 18696 CRC32 0xcf5f7255 GTID last_committed=60 sequence_number=61 rbr_only=no
SET @@SESSION.GTID_NEXT= '025fd638-89ea-11e9-a749-40f2e9cf3aaa:124'/*!*/;
# at 18696
#190626 9:33:03 server id 1614520 end_log_pos 18777 CRC32 0x9b5bd9a2 Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512783/*!*/;
BEGIN
/*!*/;
# at 18777
#190626 9:33:03 server id 1614520 end_log_pos 18893 CRC32 0xcb74bf8b Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512783/*!*/;
update tb003 set c1=SLEEP(10) where id=2
/*!*/;
# at 18893
#190626 9:33:03 server id 1614520 end_log_pos 18975 CRC32 0x2f80ec1e Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512783/*!*/;
COMMIT
/*!*/;
# at 18975
#190626 9:33:13 server id 1614520 end_log_pos 19040 CRC32 0x16f3eadd GTID last_committed=61 sequence_number=62 rbr_only=no
SET @@SESSION.GTID_NEXT= '025fd638-89ea-11e9-a749-40f2e9cf3aaa:125'/*!*/;
# at 19040
#190626 9:33:13 server id 1614520 end_log_pos 19121 CRC32 0x52c49fbe Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512793/*!*/;
BEGIN
/*!*/;
# at 19121
#190626 9:33:13 server id 1614520 end_log_pos 19237 CRC32 0x5638a3eb Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512793/*!*/;
update tb003 set c1=SLEEP(10) where id=3
/*!*/;
# at 19237
#190626 9:33:13 server id 1614520 end_log_pos 19319 CRC32 0x54716796 Query thread_id=3848 exec_time=10 error_code=0
SET TIMESTAMP=1561512793/*!*/;
COMMIT
/*!*/;

复制延迟计算方式:

在2019-06-26 09:32:50 -- 2019-06-26 09:33:03期间,Exec_Master_Log_Pos=18287,从库上分发队列GAQ为空,将last_master_timestamp设置为0,Seconds_Behind_Master为0。

在2019-06-26 09:33:04 -- 2019-06-26 09:33:13期间,分发队列GAQ的CHECKPOINT没有推进,last_master_timestamp未被更新,Exec_Master_Log_Pos还是保持18287,因此Seconds_Behind_Master为0。

在2019-06-26 09:33:14 -- 2019-06-26 09:33:23期间,Exec_Master_Log_Pos= 18631 ,对应的事务开始时间"2019-06-26 09:32:53",执行时间10秒。
在2019-06-26 09:33:18时的从库复制延迟时间计算如下:
最后binlog的时间戳( mi->rli->last_master_timestamp) = 最后binlog事件开始时间(ev->when.tv_sec)+最后binlog事件执行时间((time_t) ev->exec_time)
= "2019-06-26 09:32:53" + "10秒"
= "2019-06-26 09:33:03"
复制延迟时间(Seconds_Behind_Master) = 当前从库系统时间(time(0)) - 最后binlog的时间戳( mi->rli->last_master_timestamp) - 主从系统时间差(mi->clock_diff_with_master)
= "2019-06-26 09:33:18" - "2019-06-26 09:33:03" - "0秒"
= 15秒

MySQL Replication--复制延迟03--Seconds_Behind_Master计算的更多相关文章

  1. 浅谈MySQL Replication(复制)基本原理

    1.MySQL Replication复制进程MySQL的复制(replication)是一个异步的复制,从一个MySQL instace(称之为Master)复制到另一个MySQL instance ...

  2. mysql replication 复制的一些问题

    1   过大的复制延迟 mysql 的复制延迟是一个常见问题,现在已经有一些解决方案,如淘宝开发的一些工具 2 没有磁盘空间 复制导致磁盘空间塞满,二进制日志.中继日志或临时文件把磁盘塞满,slave ...

  3. MySQL · 答疑解惑 · 备库Seconds_Behind_Master计算

    背景 在mysql主备环境下,主备同步过程如下,主库更新产生binlog, 备库io线程拉取主库binlog生成relay log.备库sql线程执行relay log从而保持和主库同步. 理论上主库 ...

  4. 在Docker平台实现MySQL Replication(复制)

    MySQL Replication提供了数据库之间复制数据的功能,通过这个功能可以让一个数据库的数据更改自动同步到另外一个数据库.通常用这个功能来实现数据备份.数据容灾.数据冗余,进一步实现数据的读写 ...

  5. Windows 下MySql Replication(复制)配置

    环境准备 到官网下载mysql-installer-web-community-5.7.21.0.msi并安装,选择MySql Workbench,记录安装时root输入的密码. 需要安装在两台机器上 ...

  6. 你遇到过哪些原因造成MySQL异步复制延迟?

    master上多为并发事务,salve上则多为单线程回放(MySQL 5.7起,支持真正的并行回放,有所缓解) 异步复制,本来就是有一定延迟的(否则也不叫做异步了,介意的话可以改成半同步复制) sla ...

  7. MySQL异步复制延迟解决

    http://www.ttlsa.com/mysql/mysql-5-7-enhanced-multi-thread-salve/

  8. 怎样解决MySQL数据库主从复制延迟的问题---流行网站的解决办法(转载)

    像Facebook.开心001.人人网.优酷.豆瓣.淘宝等高流量.高并发的网站,单点数据库很难支撑得住,WEB2.0类型的网站中使用MySQL的 居多,要么用MySQL自带的MySQL NDB Clu ...

  9. 浅析 MySQL Replication(本文转自网络,非本人所写)

    作者:卢飞 来源:DoDBA(mysqlcode) 0.导读 本文几乎涵盖了MySQL Replication(主从复制)的大部分知识点,包括Replication原理.binlog format.复 ...

  10. 浅析 MySQL Replication(转)

    目前很多公司中的生产环境中都使用了MySQL Replication ,也叫 MySQL 复制,搭建配置方便等很多特性让 MySQL Replication 的应用很广泛,我们曾经使用过一主拖20多个 ...

随机推荐

  1. debian8 vga 文本模式下出现闪屏

    这种问题是因为 grub 里面关于 分辨率大小不对的问题. 在 debian 里面,在文件 /boot/grub/grub.cfg 里面可以添加 vga 参数配置. 如下: 在 kernel 启动参数 ...

  2. android分渠道打包,监测日活量统计(基于友盟SDK)

    客服说要看App日活,让加个统计功能. (我们技术部已经混到客服部都能直接提需求的地步) 首先接入友盟统计的SDK,在项目外层的build.gradle中添加依赖'https://dl.bintray ...

  3. IfcBuildingElement

    IfcBuildingElement /* Generated By: IFC Tools Project EXPRESS TO JAVA COMPILER: Do not edit this fil ...

  4. Look Further to Recognize Better: Learning Shared Topics and Category-Specific Dictionaries for Open-Ended 3D Object Recognition

    张宁 Look Further to Recognize Better: Learning Shared Topics and Category-Specific Dictionaries for O ...

  5. 安装opencv时ippicv下载超时

    1.手动去下载: github地址为: https://github.com/opencv/opencv_3rdparty/tree/ippicv/master_20151201/ippicv 2.查 ...

  6. postman 用环境变量Environment实现多服务器版本

    现存问题 在测试API期间,往往存在多种环境,对应IP地址(或域名也不同) 比如: Prod: http://116.62.25.57/ucows 用于开发完成发布到生产环境 Dev: http:// ...

  7. Operation之变换操作符

    buffer buffer方法的作用是缓冲组合, 第一个参数是缓冲时间, 第二个参数是缓冲个数, 第三个参数是线程 该方法简单来说就是缓存Observable中发出的新元素, 当元素达到某个数量, 或 ...

  8. Redist的主从配置

    Redis的主从复制一般用来在线备份和读写分离,提高服务器的负载能力.主数据库主要进行写操作,而从数据库负责读操作. 主从的配置: 主节点: [root@master ~]# grep -v -E & ...

  9. Python鼠标模拟

    有时候我们需要使用python执行一些脚本,可能需要让程序自动按键或自动点击鼠标,下面的代码实现了对键盘的模拟按键, 需要安装pypiwin32,当然也可以直接用ctypes来实现. 输入:pip i ...

  10. 修改IP地址之后认证信息问题

    $ ssh lvph@172.16.20.20 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOT ...