网站被封怎么,网站开发有几种语言,中小企业服务,东莞横沥邮编Seconds_Behind_Master 如何计算
以下是源码中关于延迟时间计算方法的注释说明
# 位于rpl_mi.h中定义clock_diff_with_master附近#xff08;翻阅了5.6.34和5.7.22 两个版本#xff0c;对于复制延迟的计算公式两者一致#xff09;
# 从源码注释上来看#xff0c;复制延迟…Seconds_Behind_Master 如何计算
以下是源码中关于延迟时间计算方法的注释说明
# 位于rpl_mi.h中定义clock_diff_with_master附近翻阅了5.6.34和5.7.22 两个版本对于复制延迟的计算公式两者一致
# 从源码注释上来看复制延迟的计算公式为 clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
# 该公式的含义为从库的当前系统主机时间 - 从库 SQL 线程正在执行的event的时间戳 - 主从库的系统主机之间的时间差
/*The difference in seconds between the clock of the master and the clock ofthe 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 theI/O thread does a SELECT UNIX_TIMESTAMP() on the master.how late the slave is compared to the master is computed like this:clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master*/
# clock_diff_with_master 值为主从服务器的主机时间差该值只在I/O线程启动时计算一次后续每次计算Seconds_Behind_Master字段值时是直接复用这个计算结果每次重启I/O线程时该值会重新计算long clock_diff_with_master; # master_row[0] 为从库在主库上执行SELECT UNIX_TIMESTAMP()的操作clock_diff_with_master为主从库主机的时间差计算结果mi-clock_diff_with_master(long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10));# 从rpl_slave.cc 文件中启动 I/O 线程时可以看出start_slave_thread- # 启动start slavehandle_slave_io- # 启动start io threadget_master_version_and_clock # 获取当前slave和主机之间的时间差(clock_diff_with_master)以下是源码中关于Seconds_Behind_Master 计算结果的一些判定值/*The pseudo code to compute Seconds_Behind_Master: # 阐明这是一段注释关于如何计算Seconds_Behind_Master的伪代码if (SQL thread is running) # 如果SQL线程正在运行则进入这个if判断内假设这里标记为if one{if (SQL thread processed all the available relay log) # 如果SQL线程应用完成了所有可用的relay log则进入这个if判断内假设这里标记为if two{if (IO thread is running) # 如果I/O线程正在运行则进入这个if判断内假设这里标记为if threeprint 0; # 如果if one/two/three三个条件都为真则延迟值判定为0elseprint NULL; # 如果if one/two为真if three为假则延迟值判定为NULL}elsecompute Seconds_Behind_Master; # 如果if one为真if two为假则执行公式计算延迟值}elseprint NULL; # 如果if one为假则延迟值判定为NULL
*/if (mi-rli-slave_running)
{/*Check if SQL thread is at the end of relay logChecking should be done using two conditionscondition1: compare the log positions andcondition2: compare the file names (to handle rotation case)*/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);elseprotocol-store_null();}else{long time_diff ((long)(time(0) - mi-rli-last_master_timestamp)- mi-clock_diff_with_master);/*Apparently on some systems time_diff can be 0. Here are possiblereasons related to MySQL:- the master is itself a slave of another master whose time is ahead.- somebody used an explicit SET TIMESTAMP on the master.Possible reason related to granularity-to-second of time functions(nothing to do with MySQL), which can explain a value of -1:assume the masters and slaves time are perfectly synchronized, andthat at slaves connection time, when the masters timestamp is read,it is at the very end of second 1, and (a very short time later) whenthe slaves timestamp is read it is at the very beginning of second2. Then the recorded value for master is 1 and the recorded value forslave is 2. At SHOW SLAVE STATUS time, assume that the differencebetween timestamp of slave and rli-last_master_timestamp is 0(i.e. they are in the same second), then we get 0-(2-1)-1 as a result.This confuses users, so we dont go below 0: hence the max().last_master_timestamp 0 (an impossible timestamp 1970) is aspecial marker to say consider we have caught up.*/protocol-store((longlong)(mi-rli-last_master_timestamp ?max(0L, time_diff) : 0)); # time_diff这里其实就是最终计算的Seconds_Behind_Master 值如果为负数则直接归零}
}
从源码注释上来看复制延迟的计算公式为
clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
该公式的含义为从库的当前系统主机时间 - 从库 SQL 线程正在执行的event的时间戳 - 主从库的系统主机之间的时间差
clock_diff_with_master 值为主从服务器的主机时间差该值只在I/O线程启动时计算一次后续每次计算Seconds_Behind_Master字段值时是直接复用这个计算结果每次重启I/O线程时该值会重新计算 long time_diff ((long)(time(0) - mi-rli-last_master_timestamp)- mi-clock_diff_with_master);这行代码计算了一个名为 time_diff 的长整型变量其值是当前时间通过 time(0) 获取与主实例上最后一个事件的时间戳mi-rli-last_master_timestamp之间的差异减去主从实例之间的时钟差异mi-clock_diff_with_master。这个 time_diff 的值表示当前时间与主实例最后一个事件的时间戳之间的秒数差异减去主从实例之间的时钟差异。
显示的值分别代表什么
显示NULL
1当从库没有任何需要处理的更新时如果I/O和SQL线程状态都为Yes则此字段显示为0如果有任意一个线程状态不为Yes则此字段显示为NULL
2如果从库的SQL线程没运行、SQL线程正在运行且已经消费完了所有的relay log且I/O线程没有运行则该字段显示为NULL
3如果I/O线程已经停止但还存在着relay log未重放完成时仍然会显示出复制延迟时间直到所有relay log被重放完成之后显示为NULL
显示0
1如果SQL线程和I/O线程都运行着但是处于空闲状态SQL线程已经重放完了I/O线程产生的
relay log则该字段显示为0
2当从库没有任何需要处理的更新时如果I/O和SQL线程状态都为Yes则此字段显示为0
显示数值
代表延迟的数值
clock_of_slave - last_timestamp_executed_by_SQL_thread - clock_diff_with_master
这种计算方式的局限性
网络延迟的问题
实际上这个字段是度量从库SQL线程和I/O线程之间的时间差单位为秒如果主备之间的网络非常快那么从库的I/O线程读取的主库binlog会与主库中最新的binlog非常接近所以这样计算得来得值就可以作为主备之间的数据延迟时间但是如果主备之间的网络非常慢可能导致从库SQL线程正在重放的主库binlog 非常接近从库I/O线程读取的主库binlog而I/O线程因为网络慢的原因可能读取的主库binlog远远落后于主库最新的binlog此时这么计算得来的值是不可靠的尽管这个时候有可能该字段显示为0但实际上可能从库已经落后于主库非常多了。所以对于网络比较慢的情况该值并不可靠。
如何解决网络问题带来的误判
复制实例的SQL线程可能经常追赶读取速度较慢的复制实例的I/O线程因此Seconds_Behind_Master经常显示为0即使I/O线程相对于主实例是延迟的。换句话说该列仅在快速网络中才有用。
那如何判断是否是网络的问题呢这就取决于是IO线程的延迟还是SQL线程延迟的问题。
如何判断是否IO线程还是SQL线程的延迟
通过如下两对值进行比对
第一对( File , Position ) ( Master_Log_File , Read_Master_Log_Pos )
这里面
( File , Position ) 记录了主库 binlog 的位置。( Master_Log_File , Read_Master_Log_Pos ) 记录了 IO 线程当前正在接收的二进制日志事件在主库 binlog 中的位置。
如果 ( File , Position ) 大于 ( Master_Log_File , Read_Master_Log_Pos ) 则意味着 IO 线程存在延迟。
第二对( Master_Log_File , Read_Master_Log_Pos ) ( Relay_Master_Log_File , Exec_Master_Log_Pos )
这里面( Relay_Master_Log_File, Exec_Master_Log_Pos ) 记录了 SQL 线程当前正在重放的二进制日志事件在主库 binlog 的位置。
如果 ( Relay_Master_Log_File, Exec_Master_Log_Pos ) ( Master_Log_File, Read_Master_Log_Pos ) 则意味着 SQL 线程存在延迟。
主机时间可修改
如果主库与从库的server自身的时间不一致那么只要从库复制线程启动之后没有做过任何时间变更那么这个字段的值也可以正常计算但是如果修改了server的时间则可能导致时钟偏移从而导致这个计算值不可靠
如何解决主机时间带来的误判
主机上执行date命令查看当前时间
主机命令行执行
date登录数据库执行
select now(),unix_timestamp(),from_unixtime(unix_timestamp());确保两个查询的时间符合当前的时间值如果系统时间不符合当前时间则修改时间为当前正确时间再重启复制线程。
前面提到过clock_diff_with_master 值为主从服务器的主机时间差该值只在I/O线程启动时计算一次后续每次计算Seconds_Behind_Master字段值时是直接复用这个计算结果每次重启I/O线程时该值会重新计算。因此不用担心主从的主机时间完全一致。只需要确保与当前实际时间没有太大误差即可重启复制线程会覆盖clock_diff_with_master的值。
大事务的情况
当SQL线程重放大事务时SQL线程的时间戳更新相当于被暂停了因为一个大事务的event在重放时需要很长时间才能完成虽然这个大事务也可能会有很多event但是这些event的时间戳可能全都相同此时根据计算公式可以得出无论主库是否有新的数据写入从库复制延迟仍然会持续增大也就是说此时的复制延迟值是不可靠的。所以就会出现主库停止写入之后从库复制延迟逐渐增大到某个最高值之后突然变为0的情况。
多线程复制下的波动
多线程复制则此值是基于Exec_Master_Log_Pos点的event时间戳来计算的因此可能不会反映从库最近提交的事务的位置。
从库不是read_only
如果从库上通过客户端连接进入并直接更新数据这可能导致该字段的值随机波动因为有时候event来源于主库有时候来源于从库直接更新产生的event而这个字段的值会受到直接更新产生的event的影响。
总结 对于主从库主机时间不一致的情况在I/O线程第一次启动时会计算主从之间的主机时间差在后续计算复制延迟时会把这个时间差减掉这样就可以保证正确获取到复制延迟时间但是该时间差只在I/O线程启动时才会进行计算所以当I/O线程启动之后修改了主从库的主机时间则根据计算公式会导致复制延迟时间不可靠但是当I/O线程重启之后就可以恢复因为I/O线程重启时主从之间的时间差重新计算了 在计算复制延迟时执行 SHOW SLAVE STATUS语句时会进行计算对Seconds_Behind_Master计算结果做一些判定上文源码介绍部分的伪代码注释里有讲解过这里再啰嗦一下 如果 I/O 和 SQL线程同时为 Yes且SQL线程没有做任何事情没有需要被执行的event此时直接判定复制延迟结果为0不会走公式计算延迟时间否则会走公式计算延迟时间所以在该前置条件下不会出现当主库没有写任何binlog event时从库延迟不断加大的情况 如果 SQL线程为Yes且还存在着 I/O 线程已经读取的relay log未应用完成的则会走公式计算延迟时间而不管 I/O线程是否正在运行但当SQL线程重放完成了所有relay log时如果 I/O线程不为Yes直接判定复制延迟结果为NULL 任何时候如果SQL线程不为Yes直接判定复制延迟结果为NULL。当计算出的复制延迟为负数时直接归零