作者:高鹏

文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》,深入透彻理解 MySQL 主从,GTID 相关技术知识。

源码版本:5.7.22

水平有限,如有误请谅解

本文建议横屏观看,效果更佳

一、案例来源和现象

这个案例是朋友 @peaceful 遇到的线上问题,最终线索也是他自己找到的。现象如下:

1、出现了大量很小的 relay log 如下,堆积量大约 2600 个:

...

-rw-r----- 1 mysql dba 12827 Oct 11 12:28 mysql-relay-bin.036615

-rw-r----- 1 mysql dba 4908 Oct 11 12:28 mysql-relay-bin.036616

-rw-r----- 1 mysql dba 1188 Oct 11 12:28 mysql-relay-bin.036617

-rw-r----- 1 mysql dba 5823 Oct 11 12:29 mysql-relay-bin.036618

-rw-r----- 1 mysql dba 507 Oct 11 12:29 mysql-relay-bin.036619

-rw-r----- 1 mysql dba 1188 Oct 11 12:29 mysql-relay-bin.036620

-rw-r----- 1 mysql dba 3203 Oct 11 12:29 mysql-relay-bin.036621

-rw-r----- 1 mysql dba 37916 Oct 11 12:30 mysql-relay-bin.036622

-rw-r----- 1 mysql dba 507 Oct 11 12:30 mysql-relay-bin.036623

-rw-r----- 1 mysql dba 1188 Oct 11 12:31 mysql-relay-bin.036624

-rw-r----- 1 mysql dba 4909 Oct 11 12:31 mysql-relay-bin.036625

-rw-r----- 1 mysql dba 1188 Oct 11 12:31 mysql-relay-bin.036626

-rw-r----- 1 mysql dba 507 Oct 11 12:31 mysql-relay-bin.036627

-rw-r----- 1 mysql dba 507 Oct 11 12:32 mysql-relay-bin.036628

-rw-r----- 1 mysql dba 1188 Oct 11 12:32 mysql-relay-bin.036629

-rw-r----- 1 mysql dba 454 Oct 11 12:32 mysql-relay-bin.036630

-rw-r----- 1 mysql dba 6223 Oct 11 12:32 mysql-relay-bin.index

2、主库错误日志有如下错误

2019-10-11T12:31:26.517309+08:00 61303425 [Note] While initializing dump thread for slave with UUID , found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(61303421).

2019-10-11T12:31:26.517489+08:00 61303425 [Note] Start binlog_dump to master_thread_id(61303425) slave_server(19304313), pos(, 4)

2019-10-11T12:31:44.203747+08:00 61303449 [Note] While initializing dump thread for slave with UUID , found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(61303425).

2019-10-11T12:31:44.203896+08:00 61303449 [Note] Start binlog_dump to master_thread_id(61303449) slave_server(19304313), pos(, 4)

二、slave_net_timeout 参数分析

实际上第一眼看这个案例我也觉得很奇怪,因为很少有人会去设置 slave_net_timeout 参数,同样我们也没有设置过,因此关注较少。但是 @peaceful 自己找到了可能出现问题的设置就是当前从库 slave_net_timeout 参数设置为 10。我就顺着这个线索往下分析,我们先来看看 slave_net_timeout 参数的功能。

当前看来从库的 slave_net_timeout 有如下两个功能:

1、设置 IO 线程在空闲情况下(没有 Event 接收的情况下)的连接超时时间。

这个参数 5.7.7 过后是 60 秒,以前是 3600 秒,修改后需要重启主从才会生效。

2、如果 change master 没有指定 MASTER_HEARTBEAT_PERIOD 的情况下会设置为 slave_net_timeout/2

一般我们配置主从都没有去指定这个心跳周期,因此就是 slave_net_timeout/2,它控制的是如果在主库没有 Event 产生的情况下,多久发送一个心跳 Event 给从库的 IO 线程,用于保持连接。但是一旦我们配置了主从(change master)这个值就定下来了,不会随着 slave_net_timeout 参数的更改而更改,我们可以在 slave_master_info 表中找到相应的设置如下:

mysql> select Heartbeat from slave_master_info \G

*************************** 1. row ***************************

Heartbeat: 30

1 row in set (0.01 sec)

如果我们要更改这个值只能重新 change master 才行。

三、原因总结

如果满足下面三个条件,将会出现案例中的故障:

主从中的 MASTER_HEARTBEAT_PERIOD 的值大于从库 slave_net_timeout

主库当前压力很小持续 slave_net_timeout 设置时间没有产生新的 Event

之前主从有一定的延迟

那么这种情况下在主库心跳 Event 发送给从库的IO线程之前,IO 线程已经断开了。断开后 IO 线程会进行重连,每次重连将会生成新的 relay log,但是这些 relay log 由于延迟问题不能清理就出现了案例中的情况。

下面是官方文档中关于这部分说明:

If you are logging master connection information to tables, MASTER_HEARTBEAT_PERIOD can be seen

as the value of the Heartbeat column of the mysql.slave_master_info table.

Setting interval to 0 disables heartbeats altogether. The default value for interval is equal to the

value of slave_net_timeout divided by 2.

Setting @@global.slave_net_timeout to a value less than that of the current heartbeat interval

results in a warning being issued. The effect of issuing RESET SLAVE on the heartbeat interval is to

reset it to the default value.

四、案例模拟

有了理论基础就很好了模拟了,延迟这一点我模拟的时候关闭了从库的 SQL 线程来模拟 relay log 积压的情况,因为这个案例和 SQL 线程没有太多的关系。

提前配置好主从,查看当前的心跳周期和 slave_net_timeout 参数如下:

mysql> show variables like '%slave_net_timeout%';

+-------------------+-------+

| Variable_name | Value |

+-------------------+-------+

| slave_net_timeout | 60 |

+-------------------+-------+

1 row in set (0.01 sec)

mysql> select Heartbeat from slave_master_info \G

*************************** 1. row ***************************

Heartbeat: 30

1 row in set (0.00 sec)

1、停止从库的 SQL 线程

stop slave sql_thread;

2、设置 slave_net_timeout 为 10

mysql> set global slave_net_timeout=10;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;

+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Level | Code | Message |

+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+

| Warning | 1704 | The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout. |

+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+

1 row in set (0.00 sec)

可以看到这里实际上已经有一个警告了。

3、重启 IO 线程

这样才会让 slave_net_timeout 参数生效

mysql> stop slave ;

Query OK, 0 rows affected (0.01 sec)

mysql> start slave io_thread;

Query OK, 0 rows affected (0.01 sec)

4、观察现象

大概每 10 秒会生成一个 relay log 文件如下:

-rw-r----- 1 mysql mysql 500 2019-09-27 23:48:32.655001361 +0800 relay.000142

-rw-r----- 1 mysql mysql 500 2019-09-27 23:48:42.943001355 +0800 relay.000143

-rw-r----- 1 mysql mysql 500 2019-09-27 23:48:53.293001363 +0800 relay.000144

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:03.502000598 +0800 relay.000145

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:13.799001357 +0800 relay.000146

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:24.055001354 +0800 relay.000147

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:34.280001827 +0800 relay.000148

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:44.496001365 +0800 relay.000149

-rw-r----- 1 mysql mysql 500 2019-09-27 23:49:54.789001353 +0800 relay.000150

-rw-r----- 1 mysql mysql 500 2019-09-27 23:50:05.485001371 +0800 relay.000151

-rw-r----- 1 mysql mysql 500 2019-09-27 23:50:15.910001430 +0800 relay.000152

大概每 10 秒主库的日志会输出如下日志:

2019-10-08T02:27:24.996827+08:00 217 [Note] While initializing dump thread for slave with UUID <010fde77-2075-11e9-ba07-5254009862c0>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(216).

2019-10-08T02:27:24.998297+08:00 217 [Note] Start binlog_dump to master_thread_id(217) slave_server(953340), pos(, 4)

2019-10-08T02:27:35.265961+08:00 218 [Note] While initializing dump thread for slave with UUID <010fde77-2075-11e9-ba07-5254009862c0>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(217).

2019-10-08T02:27:35.266653+08:00 218 [Note] Start binlog_dump to master_thread_id(218) slave_server(953340), pos(, 4)

2019-10-08T02:27:45.588074+08:00 219 [Note] While initializing dump thread for slave with UUID <010fde77-2075-11e9-ba07-5254009862c0>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(218).

2019-10-08T02:27:45.589814+08:00 219 [Note] Start binlog_dump to master_thread_id(219) slave_server(953340), pos(, 4)

2019-10-08T02:27:55.848558+08:00 220 [Note] While initializing dump thread for slave with UUID <010fde77-2075-11e9-ba07-5254009862c0>, found a zombie dump thread with the same UUID. Master is killing the zombie dump thread(219).

2019-10-08T02:27:55.849442+08:00 220 [Note] Start binlog_dump to master_thread_id(220) slave_server(953340), pos(, 4)

这个日志就和案例中的一模一样了。

解决问题

知道原因后解决也就很简单了我们只需设置 slave_net_timeout 参数为 MASTER_HEARTBEAT_PERIOD 的 2 倍就可以了,设置后重启主从即可。

五、实现方式

这里我们将通过简单的源码调用分析来看看到底 slave_net_timeout 参数和 MASTER_HEARTBEAT_PERIOD 对主从的影响。

1、从库使用参数 slave_net_timeout

从库IO线程启动时候会通过参数 slave_net_timeout 设置超时:

->connect_to_master

-> mysql_options

case MYSQL_OPT_CONNECT_TIMEOUT: //MYSQL_OPT_CONNECT_TIMEOUT

mysql->options.connect_timeout= *(uint*) arg;

break;

而在建立和主库的连接时候会使用这个值

connect_to_master

->mysql_real_connect

-> get_vio_connect_timeout

timeout_sec= mysql->options.connect_timeout;

因此我们也看到了 slave_net_timeout 参数只有在 IO 线程重启的时候才会生效

2、从库设置 MASTER_HEARTBEAT_PERIOD 值

在每次使用从库 change master 时候会设置这个值如下,默认为 slave_net_timeout/2:

->change_master

->change_receive_options

mi->heartbeat_period= min(SLAVE_MAX_HEARTBEAT_PERIOD,

(slave_net_timeout/2.0f));

因此我们看到只有 change master 才会重新设置这个值,重启主从是不会重新设置的。

3、使用 MASTER_HEARTBEAT_PERIOD 值

每次 IO 线程启动时候会将这个值传递给主库的 DUMP 线程,方式应该是通过构建语句 ‘SET @master_heartbeat_period’ 来完成的。如下:

->handle_slave_io

->get_master_version_and_clock

if (mi->heartbeat_period != 0.0)

{

char llbuf[22];

const char query_format[]= "SET @master_heartbeat_period= %s";

char query[sizeof(query_format) - 2 + sizeof(llbuf)];

主库启动 DUMP 线程的时候会通过搜索的方式找到这个值如下

->Binlog_sender::init

->Binlog_sender::init_heartbeat_period

user_var_entry *entry=

(user_var_entry*) my_hash_search(&m_thd->user_vars, (uchar*) name.str,

name.length);

m_heartbeat_period= entry ? entry->val_int(&null_value) : 0;

4、DUMP 线程使用 MASTER_HEARTBEAT_PERIOD 发送心跳 Event

这里主要是通过一个超时等待来完成,如下:

->Binlog_sender::wait_new_events

->Binlog_sender::wait_with_heartbeat

set_timespec_nsec(&ts, m_heartbeat_period); //心跳超时

ret= mysql_bin_log.wait_for_update_bin_log(m_thd, &ts);//等待

if (ret != ETIMEDOUT && ret != ETIME) //如果是正常收到则收到信号,说明有新的Event到来,否则如果是超时则发送心跳Event

break; //正常返回0 是超时返回ETIMEDOUT 继续循环

if (send_heartbeat_event(log_pos)) //发送心跳Event

return 1;

5、重连会杀掉可能的存在的 DUMP 线程

根据 UUID 进行比对如下:

->kill_zombie_dump_threads

Find_zombie_dump_thread find_zombie_dump_thread(slave_uuid);

THD *tmp= Global_THD_manager::get_instance()->

find_thd(&find_zombie_dump_thread);

if (tmp)

{

/*

Here we do not call kill_one_thread() as

it will be slow because it will iterate through the list

again. We just to do kill the thread ourselves.

*/

if (log_warnings > 1)

{

if (slave_uuid.length())

{

sql_print_information("While initializing dump thread for slave with "

"UUID , found a zombie dump thread with the "

"same UUID. Master is killing the zombie dump "

"thread(%u).", slave_uuid.c_ptr(),

tmp->thread_id());

}//这里就是本案例中的日志了

.....

这里我们看到了案例中的日志。

6、关于 DUMP 线程流程图

最后给出一张来自我《 MySQL 主从原理 32 讲》第 17 节中 DUMP 线程的流程图如下:

mysql relay_技术分享 | MySQL:产生大量小 relay log 的故障一例相关推荐

  1. mysql 1280_技术分享 | MySQL 一次奇怪的故障分析

    一.问题来源 这是一个朋友问我的典型案例.整个故障现象表现为,MySQL 数据库频繁的出现大量的请求不能响应.下面是一些他提供的证据: 1. show processlist从状态信息来看出现如下情况 ...

  2. MySQL read-c_技术分享 | MySQL C API 参数 MYSQL_OPT_READ_TIMEOUT 的一些行为分析

    作者:戴岳兵 MYSQL_OPT_READ_TIMEOUT 是 MySQL c api 客户端中用来设置读取超时时间的参数.在 MySQL 的官方文档中,该参数的描述是这样的: MYSQL_OPT_R ...

  3. mysql dbuild_config_技术分享 | MySQL Test 初探

    什么是 MySQL Test? MySQL Test 是 MySQL 发行版本中集成 all-in-one 测试框架,用于做 mysql 服务的单元,回归和一致性测试,并提供了运行单元测试和创建新单元 ...

  4. mysql TMM_技术分享 | MySQL:timestamp 时区转换导致 CPU %sy 高的问题

    这个问题是一个朋友遇到的@风云,并且这位朋友已经得出了近乎正确的判断,下面进行一些描述. 一.问题展示下面是问题当时的系统负载如下: 我们可以看到 40.4%sy 正是系统调用负载较高的表现,随即朋友 ...

  5. mysql优化说出九条_技术分享 | MySQL 优化:为什么 SQL 走索引还那么慢?

    原标题:技术分享 | MySQL 优化:为什么 SQL 走索引还那么慢? 背景 2019-01-11 9:00-10:00 一个 MySQL 数据库把 CPU 打满了. 硬件配置:256G 内存,48 ...

  6. mysql数据库j电子课件,MYSQL数据库技术分享PPT演示课件

    <MYSQL数据库技术分享PPT演示课件>由会员分享,可在线阅读,更多相关<MYSQL数据库技术分享PPT演示课件(29页珍藏版)>请在人人文库网上搜索. 1.数据库技术分享, ...

  7. 技术分享 | MySQL 突如其来的主从复制延迟

    作者:刘开洋 爱可生交付服务团队北京 DBA,对数据库及周边技术有浓厚的学习兴趣,喜欢看书,追求技术. 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源 ...

  8. 技术分享 | MySQL中MGR中SECONDARY节点磁盘满,导致mysqld进程被OOM Killed

    欢迎来到 GreatSQL社区分享的MySQL技术文章,如有疑问或想学习的内容,可以在下方评论区留言,看到后会进行解答 在MGR测试中,人为制造磁盘满问题后,节点被oom killed 问题描述 在对 ...

  9. mysql 的connect 设置 无法点next_技术分享 | MySQL 使用 MariaDB 审计插件

    作者:姚远 专注于 Oracle.MySQL 数据库多年,Oracle 10G 和 12C OCM,MySQL 5.6 ,5.7,8.0 OCP.现在鼎甲科技任顾问,为同事和客户提供数据库培训和技术支 ...

最新文章

  1. Shell 下记录程序运行时间
  2. Python第三章-字符串
  3. StringBuilder类
  4. jetbrick-template 1.1.0 发布,支持 #tag, #macro, layout
  5. tomcat,很多时候,可以在服务server.xml中可以实现一些效果
  6. 回顾 | 进击吧! Blazor !第三期 信息交互
  7. Martin Odersky Scala编程公开课 第三周作业
  8. 标注工具——VoTT的调试笔记
  9. 【CCCC】L3-023 计算图 (30分),dfs搜索+偏导数计算
  10. coalesce函数_什么是SQL Server COALESCE()函数?
  11. 人民币真的升值了吗?
  12. 航空订票系统java_航空订票系统(JAVA+SSH+MYSQL)
  13. delphi自定义类大体描述
  14. 电阻式触摸屏UI设计
  15. python linux 执行scp,python 使用标准库连接linux实现scp和执行命令
  16. [Irving] Android 点击两次返回退出系统
  17. 信息系统高级项目管理师英语词汇(一)-常见计算机技术词汇
  18. 9.11 myl模拟赛
  19. 阿里云服务器的购买以及使用
  20. 华为OD机试 - 无向图染色

热门文章

  1. 编程方法学11:Gimage
  2. 读书笔记《单核工作法》_6:颠倒you'xian'ji
  3. 转载:独立思考能力吞噬
  4. 科大星云诗社动态20210501
  5. 云炬随笔20171205
  6. 计算机组成原理试题2,计算机组成原理试题2.doc
  7. 项目经理应该把30%的时间用在编程上
  8. C#中写简单的COM+组件
  9. Windows 外壳扩展编程入门实例
  10. IDEA 单元测试报错:Class not found