MySQL Replication--复制延迟01--源码瞎猜
本人完全不懂MySQL源码,以下文字纯属瞎猜,如有误导,概不负责!、
源码版本:MySQL 5.6.28
在sql/rpl_slave.cc文件中,time_diff的计算代码为:
/*
The pseudo code to compute Seconds_Behind_Master:
if (SQL thread is running)
{
if (SQL thread processed all the available relay log)
{
if (IO thread is running)
print 0;
else
print NULL;
}
else
compute Seconds_Behind_Master;
}
else
print NULL;
*/
if (mi->rli->slave_running)
{
/* Check if SQL thread is at the end of relay log
Checking should be done using two conditions
condition1: compare the log positions and
condition2: 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);
else
protocol->store_null();
}
else
{
long time_diff= ((long)(time() - mi->rli->last_master_timestamp)
- mi->clock_diff_with_master);
/*
Apparently on some systems time_diff can be <0. Here are possible
reasons 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 master's and slave's time are perfectly synchronized, and
that at slave's connection time, when the master's timestamp is read,
it is at the very end of second 1, and (a very short time later) when
the slave's timestamp is read it is at the very beginning of second
2. Then the recorded value for master is 1 and the recorded value for
slave is 2. At SHOW SLAVE STATUS time, assume that the difference
between 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 don't go below 0: hence the max(). last_master_timestamp == 0 (an "impossible" timestamp 1970) is a
special marker to say "consider we have caught up".
*/
protocol->store((longlong)(mi->rli->last_master_timestamp ?
max(0L, time_diff) : ));
}
}
else
{
protocol->store_null();
}
1、当SQL线程停止时,返回NULL
2、当SLAVE正常运行时,如果SQL线程执行的位置是relay log的最后位置则返回0,否则返回NULL
3、当SLAVE正常运行时,复制延迟时间=当前从库系统时间(time(0)) - SQL线程处理的最后binlog的时间戳( mi->rli->last_master_timestamp) - 主从系统时间差(mi->clock_diff_with_master)
主从系统时间差(mi->clock_diff_with_master)
在sql/rpl_slave.cc文件中,主从系统时间差计算代码如下:
/*
Compare the master and slave's clock. Do not die if master's clock is
unavailable (very old master not supporting UNIX_TIMESTAMP()?).
*/ DBUG_EXECUTE_IF("dbug.before_get_UNIX_TIMESTAMP",
{
const char act[]=
"now "
"wait_for signal.get_unix_timestamp";
DBUG_ASSERT(opt_debug_sync_timeout > );
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};); master_res= NULL;
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*) ) - strtoul(master_row[], , ));
mysql_mutex_unlock(&mi->data_lock);
}
else if (check_io_slave_killed(mi->info_thd, mi, NULL))
goto slave_killed_err;
else if (is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
"Get master clock failed with error: %s", mysql_error(mysql));
goto network_err;
}
else
{
mysql_mutex_lock(&mi->data_lock);
mi->clock_diff_with_master= ; /* The "most sensible" value */
mysql_mutex_unlock(&mi->data_lock);
sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, "
"do not trust column Seconds_Behind_Master of SHOW "
"SLAVE STATUS. Error: %s (%d)",
mysql_error(mysql), mysql_errno(mysql));
}
if (master_res)
{
mysql_free_result(master_res);
master_res= NULL;
}
主从系统时间差=从库当前时间(time((time_t*) 0)) - 主库当前时间(UNIX_TIMESTAMP()),而主库时间是到主库上执行SELECT UNIX_TIMESTAMP(),然后取执行结果(strtoul(master_row[0], 0, 10))。
clock_diff_with_master的值是在IO线程启动时计算的,如果中途修改过主库时间,会导致clock_diff_with_master的值出现偏差。
从库SQL线程读取到relay log中的事件但未开始执行前就会更新last_master_timestamp的值,更新操作以event为单位。
非并行复制下last_master_timestamp计算
在sql/rpl_slave.cc文件中exec_relay_log_event方法中,计算非并行复制的last_master_timestamp的代码如下:
/**
Top-level function for executing the next event in the relay log.
This is called from the SQL thread. This function reads the event from the relay log, executes it, and
advances the relay log position. It also handles errors, etc. This function may fail to apply the event for the following reasons: - The position specfied by the UNTIL condition of the START SLAVE
command is reached. - It was not possible to read the event from the log. - The slave is killed. - An error occurred when applying the event, and the event has been
tried slave_trans_retries times. If the event has been retried
fewer times, 0 is returned. - init_info or init_relay_log_pos failed. (These are called
if a failure occurs when applying the event.) - An error occurred when updating the binlog position. @retval 0 The event was applied. @retval 1 The event was not applied.
*/
static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{
DBUG_ENTER("exec_relay_log_event"); /*
We acquire this mutex since we need it for all operations except
event execution. But we will release it in places where we will
wait for something for example inside of next_event().
*/
mysql_mutex_lock(&rli->data_lock); /*
UNTIL_SQL_AFTER_GTIDS requires special handling since we have to check
whether the until_condition is satisfied *before* the SQL threads goes on
a wait inside next_event() for the relay log to grow. This is reuired since
if we have already applied the last event in the waiting set but since he
check happens only at the start of the next event we may end up waiting
forever the next event is not available or is delayed.
*/
if (rli->until_condition == Relay_log_info::UNTIL_SQL_AFTER_GTIDS &&
rli->is_until_satisfied(thd, NULL))
{
rli->abort_slave= ;
mysql_mutex_unlock(&rli->data_lock);
DBUG_RETURN();
} Log_event *ev = next_event(rli), **ptr_ev; DBUG_ASSERT(rli->info_thd==thd); if (sql_slave_killed(thd,rli))
{
mysql_mutex_unlock(&rli->data_lock);
delete ev;
DBUG_RETURN();
}
if (ev)
{
enum enum_slave_apply_event_and_update_pos_retval exec_res; ptr_ev= &ev;
/*
Even if we don't execute this event, we keep the master timestamp,
so that seconds behind master shows correct delta (there are events
that are not replayed, so we keep falling behind). If it is an artificial event, or a relay log event (IO thread generated
event) or ev->when is set to 0, or a FD from master, or a heartbeat
event with server_id '0' then we don't update the last_master_timestamp.
*/
if (!(rli->is_parallel_exec() ||
ev->is_artificial_event() || ev->is_relay_log_event() ||
ev->when.tv_sec == || ev->get_type_code() == FORMAT_DESCRIPTION_EVENT ||
ev->server_id == ))
{
rli->last_master_timestamp= ev->when.tv_sec + (time_t) ev->exec_time;
DBUG_ASSERT(rli->last_master_timestamp >= );
}
其中when.tv_sec是事件在主库上的开始时间,而ev->exec_time在主库上的执行时间,只有Query_log_event和Load_log_event才会统计exec_time。
并行复制下last_master_timestamp计算
并行复制有一个分发队列gaq,sql线程将binlog事务读取到gaq,然后再分发给worker线程执行。并行复制时,binlog事件是并发穿插执行的,gaq中有一个checkpoint点称为lwm, lwm之前的binlog都已经执行,而lwm之后的binlog有些执行有些没有执行。
假设worker线程数为2,gap有1,,,,,,,8个事务。worker 1已执行的事务为1 , woker 2执行的事务为2 ,那么lwm为4。 并行复制更新gap checkpiont时,会推进lwm点,同时更新last_master_timestamp为lwm所在事务结束的event的时间。因此,并行复制是在事务执行完成后才更新last_master_timestamp,更新是以事务为单位。同时更新gap checkpiont还受slave_checkpoint_period参数的影响。 这导致并行复制下和非并行复制统计延迟存在差距,差距可能为slave_checkpoint_period + 事务在备库执行的时间。这就是为什么在并行复制下有时候会有很小的延迟,而改为非并行复制时反而没有延迟的原因。 另外当sql线程等待io线程时且gaq队列为空时,会将last_master_timestamp设为0。同样此时认为没有延迟,计算得出seconds_Behind_Master为0。 抄自https://www.kancloud.cn/taobaomysql/monthly/140089
参考
https://www.kancloud.cn/taobaomysql/monthly/140089
MySQL Replication--复制延迟01--源码瞎猜的更多相关文章
- 浅谈MySQL Replication(复制)基本原理
1.MySQL Replication复制进程MySQL的复制(replication)是一个异步的复制,从一个MySQL instace(称之为Master)复制到另一个MySQL instance ...
- FatFsVersion0.01源码分析
目录 一.API的函数功能简述 二.FATFS主要数据结构 1.FAT32文件系统的结构 2.FATFS主要数据结构 ① FATFS ② DIR ③ FIL ④ FILINFO ⑤ wi ...
- mysql replication 复制的一些问题
1 过大的复制延迟 mysql 的复制延迟是一个常见问题,现在已经有一些解决方案,如淘宝开发的一些工具 2 没有磁盘空间 复制导致磁盘空间塞满,二进制日志.中继日志或临时文件把磁盘塞满,slave ...
- Linux下MySQL、Apache、PHP源码安装全程实录(CentOS 6.4)
转自http://www.zjmainstay.cn/lamp-config 本文记录了我自己配置LAMP的全过程,借此记录一下,同时希望能够帮助一下需要帮助的LINUX新人,跟我一起学习,一起进步. ...
- MySQL Connector/C++ 8.0 源码编译
平台 ubuntu 16.04 参考文档: https://dev.mysql.com/doc/dev/connector-cpp/8.0/building.html 下载源码 访问 https:// ...
- 在Docker平台实现MySQL Replication(复制)
MySQL Replication提供了数据库之间复制数据的功能,通过这个功能可以让一个数据库的数据更改自动同步到另外一个数据库.通常用这个功能来实现数据备份.数据容灾.数据冗余,进一步实现数据的读写 ...
- mysql 5.6.23的源码安装
http://634871.blog.51cto.com/624871/1325914 首先删除系统自带的mysql rpm -qa | grep mysql rpm -e mysql //普 ...
- React 16 源码瞎几把解读 【二】 react组件的解析过程
一.一个真正的react组件编译后长啥样? 我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构.一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周 ...
- 自制小工具大大加速MySQL SQL语句优化(附源码)
引言 优化SQL,是DBA常见的工作之一.如何高效.快速地优化一条语句,是每个DBA经常要面对的一个问题.在日常的优化工作中,我发现有很多操作是在优化过程中必不可少的步骤.然而这些步骤重复性的执行,又 ...
随机推荐
- sql 各种依赖关系解释
1.数据依赖 数据依赖指的是通过一个关系中属性间的相等与否体现出来的数据间的相互关系,其中最重要的是函数依赖和多值依赖. 2.函数依赖 设X,Y是关系R的两个属性集合,当任何时刻R中的任意两个元组中的 ...
- 【计算机视觉】黄金标准算法Gold Standard algorithm
前言 最近有关于3DMM的内容,博主也只是看了个大概,并没有深入了解算法的实现原理和过程.昨天实习生问关于黄金标准算法的推导,博主也就参考一些资料熟悉了这个算法的实现过程.不太了解使用这个算法的前因后 ...
- mysql8.0 caching_sha2_password的坑
先来解释一下为什么会报这个错,在mysql8之前的版本使用的密码加密规则是mysql_native_password,但是在mysql8则是caching_sha2_password. 解决方案有很多 ...
- 安卓 App 性能专项测试之流畅度深度解析-上篇
指标背景 流畅度,顾名思义是用户感知使用App页面时的流畅情况,"App卡不卡",这是用户最直接的感受. 但是要用量化之后的数据衡量流畅度,在Android平台这边并没有直接有效的 ...
- html5传感器
html5传感器(注意苹果和安卓方向是相反的 回调函数触发的速度苹果要快很多 设置坐标不要设置在回调函数里)以下是代码<pre><!DOCTYPE html><html ...
- springboot2.0以后的junit
只需要引入: <dependency> <groupId>junit</groupId> <artifactId>junit</artifactI ...
- js中Function引用类型中一些常见且有用的方法和属性
Function类型 函数由于是Function类型的一个实例,所以函数名就是一个指向函数对象的指针,不会与某个函数死死的连接在一起,这也导致了js中没有真正的重载,但好处是,函数对象可以作为另一个函 ...
- 53 容器(八)——TreeMap 红黑树
红黑树是比较难以理解的一种数据结构.它能从10亿数据中进行10几次比较就能查找到需要的数据.效率非常高. 理解起内部结构也难. 现阶段我们知道有这种东西就行了. 参考文章: https://www.j ...
- Go语言【数据结构】数组
数组 简介 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型例如整形.字符串或者自定义类型.数组形式 numbers[0], numbers[1] ..., nu ...
- MySQl数据库面试题
1. MySQL中索引什么作用? 索引的定义和创建的目的 1) 索引是对数据库表中一列或者多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息 2) 索引的分类:主键索引,唯一索引,常规 ...