Mysql 5.7 Gtid内部学习(九) 实际案例(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 简书地址: http://www.jianshu.com/p/2c25842d58d3

本案例是一个朋友的案例他也写了出来如下:
https://mp.weixin.qq.com/s/XSnFkuYzIlGWMaXIl-oPeQ
但是和他交流后他也准备改因为分析有一些小问题。


一、触发条件

  • binlog_gtid_simple_recovery=false。
  • 5.7.6以上版本。
  • Gtid 关闭或者Gtid中途开启有大量的未开启Gtid的binlog。

二、本案例回顾

  • 版本:MySQL版本 5.7.19。
  • 故障为:大概每半小时发生一次故障,整个Mysql压力巨大,很多简单的操作都相应缓慢。使用iotop,top等工具都发现Mysql某个线程有大量的I/O。
  • 分析方法:使用strace发现有大量的binlog文件读取。
  • binlog_gtid_simple_recovery=false。
  • Gtid关闭,中途开启,但是留下了很多未开启Gtid的binlog。
  • 数据库没有重启,但是由于expire_logs_days触发了binlog删除。

三、故障分析

其实本案例就是前文第七部分总结中的:

Gtid关闭,simple_recovery=flase
5.7.6以上:这种方式一定得到正确的Gtid集合
重启Mysql不扫秒全部的binlog,如果是中途打开GTID重启任然需要扫描多个binlog因为需要找到Gtid event。
purge binlog或者超过参数expire_logs_days参数设置不触发全binlog扫描,如果是中途打开GTID重启任然需要扫描多个binlog因为需要找到Gtid event。

从案例中我们得知是中途开启的Gtid,但是留下了很多未开启Gtid的binlog,从第六部分源码bool MYSQL_BIN_LOG::init_gtid_sets()函数的分析,我们知道删除binlog后也会触发正向查找来获取gtid_purged(Gtid_state.lost_gtids)。当读取到第一个binlog的时候虽然获取到了PREVIOUS GTID EVENT但是没有GTID EVENT,而simple_recovery=flase所以需要继续查找下一个文件,直到找到同时包含PREVIOUS GTID EVENT和GTID EVENT的 那个binlog才会停止,那么显然这种情况下那些Gtid关闭的时候生成的binlog将会全部扫描一遍,如果量大那么代价将是巨大的。
而案例中每半个小时会触发一次binlog切换,因为触发超过expire_logs_days参数设置导致binlog进行删除,触发了大量的binlog扫描。
显然有了前面的基础这个案例很容易分析。

四、案例模拟

这个案例非常好模拟。我打算直接使用strace查看。因为不是每位朋友都能方便使用GDB调试。
使用测试版本社区版本5.7.17:

+---------------+-----------+
| Log_name      | File_size |
+---------------+-----------+
| binlog.000027 |       198 |
| binlog.000028 |       198 |
| binlog.000029 |       198 |
| binlog.000030 |       198 |
| binlog.000031 |       198 |
| binlog.000032 |       198 |
| binlog.000033 |       198 |
| binlog.000034 |       198 |
| binlog.000035 |       198 |
| binlog.000036 |       198 |
| binlog.000037 |       198 |
| binlog.000038 |       198 |
| binlog.000039 |       198 |
| binlog.000040 |       198 |
| binlog.000041 |       198 |
| binlog.000042 |       198 |
| binlog.000043 |       154 |
+---------------+-----------+

mysql> show variables like '%gtid%';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| binlog_gtid_simple_recovery      | OFF       |
| enforce_gtid_consistency         | ON        |
| gtid_executed_compression_period | 1000      |
| gtid_mode                        | OFF       |
| gtid_next                        | AUTOMATIC |
| gtid_owned                       |           |
| gtid_purged                      |           |
| session_track_gtids              | OFF       |
+----------------------------------+-----------+
8 rows in set (0.02 sec)
mysql> show variables like '%expir%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| disconnect_on_expired_password | ON    |
| expire_logs_days               | 1     |
+--------------------------------+-------+
2 rows in set (0.06 sec)

然后我修改了系统时间同时Mysql开启Gtid

[root@test1 ~]# date -s '2017-12-13 10:10:10'
Wed Dec 13 10:10:10 CST 2017
mysql> set global gtid_mode=1;
Query OK, 0 rows affected (0.02 sec)

mysql> set global gtid_mode=2;
Query OK, 0 rows affected (0.01 sec)

mysql> set global gtid_mode=3;
Query OK, 0 rows affected (0.02 sec)

mysql> show variables like '%gtid_mode%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| gtid_mode     | ON    |
+---------------+-------+
1 row in set (0.02 sec)

到一步我们已经达到了触发的标准,只要手动触发一次flush binary logs,让binlog刷新就会看到。当然线上是binlog满了做的切换。
这个时候开始做strace,并且做flush tables,我们观察到

mysql> flush binary logs;
Query OK, 0 rows affected (0.30 sec)

strace:

[pid  6551] 10:17:15.936738 read(62, "/mysql/mysql5.7.17/binlog.000027"..., 528) = 528 <0.000039>
[pid  6551] 10:17:15.936834 stat("/mysql/mysql5.7.17/binlog.000027", {st_mode=S_IFREG|0640, st_size=198, ...}) = 0 <0.000025>
[pid  6551] 10:17:15.936925 lseek(3, 0, SEEK_SET) = 0 <0.000017>
[pid  6551] 10:17:15.936983 read(3, "/mysql/mysql5.7.17/binlog.000043"..., 165) = 165 <0.000018>
[pid  6551] 10:17:15.937076 lstat("/mysql", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000020>
[pid  6551] 10:17:15.937144 lstat("/mysql/mysql5.7.17", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000586>
[pid  6551] 10:17:15.937819 unlink("/mysql/mysql5.7.17/binlog.000027") = 0 <0.000109>
[pid  6551] 10:17:15.938009 stat("/mysql/mysql5.7.17/binlog.000028", {st_mode=S_IFREG|0640, st_size=198, ...}) = 0 <0.000021>
[pid  6551] 10:17:15.938119 lstat("/mysql", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000020>
[pid  6551] 10:17:15.938228 lstat("/mysql/mysql5.7.17", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000021>
[pid  6551] 10:17:15.938314 unlink("/mysql/mysql5.7.17/binlog.000028") = 0 <0.000073>
.....
[pid  6551] 10:17:15.954677 lstat("/mysql/mysql5.7.17", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000019>
[pid  6551] 10:17:15.954756 unlink("/mysql/mysql5.7.17/binlog.000041") = 0 <0.000099>
[pid  6551] 10:17:15.954920 stat("/mysql/mysql5.7.17/binlog.000042", {st_mode=S_IFREG|0640, st_size=198, ...}) = 0 <0.000021>
[pid  6551] 10:17:15.955022 lstat("/mysql", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000018>
[pid  6551] 10:17:15.955087 lstat("/mysql/mysql5.7.17", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 <0.000018>
[pid  6551] 10:17:15.955159 unlink("/mysql/mysql5.7.17/binlog.000042") = 0 <0.000130>

受限篇幅我这里删除了一些。我们看到很多read/lseek系统调用正是读取binlog的证据。
至此整个案例模拟完成。

五、总结

前文已经描述过在5.7.6以上binlog_gtid_simple_recovery应该设置为true,这样可以避免可能的大量的binlog的扫描。具体分析可以参考第七节和从第六部分源码bool MYSQL_BIN_LOG::init_gtid_sets()函数的分析。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
54 3
|
2月前
|
SQL 关系型数据库 MySQL
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
171 0
案例剖析:MySQL唯一索引并发插入导致死锁!
|
2月前
|
SQL 关系型数据库 MySQL
案例剖析,MySQL共享锁引发的死锁问题!
案例剖析,MySQL共享锁引发的死锁问题!
|
2月前
|
消息中间件 关系型数据库 MySQL
大数据-117 - Flink DataStream Sink 案例:写出到MySQL、写出到Kafka
大数据-117 - Flink DataStream Sink 案例:写出到MySQL、写出到Kafka
181 0
|
9天前
|
关系型数据库 MySQL 数据库
数据库数据恢复—MYSQL数据库文件损坏的数据恢复案例
mysql数据库文件ibdata1、MYI、MYD损坏。 故障表现:1、数据库无法进行查询等操作;2、使用mysqlcheck和myisamchk无法修复数据库。
|
2月前
|
关系型数据库 MySQL 数据库
一个 MySQL 数据库死锁的案例和解决方案
本文介绍了一个 MySQL 数据库死锁的案例和解决方案。
136 3
|
2月前
|
存储 关系型数据库 MySQL
基于案例分析 MySQL 权限认证中的具体优先原则
【10月更文挑战第26天】本文通过具体案例分析了MySQL权限认证中的优先原则,包括全局权限、数据库级别权限和表级别权限的设置与优先级。全局权限优先于数据库级别权限,后者又优先于表级别权限。在权限冲突时,更严格的权限将被优先执行,确保数据库的安全性与资源合理分配。
|
2月前
|
关系型数据库 MySQL Java
Django学习二:配置mysql,创建model实例,自动创建数据库表,对mysql数据库表已经创建好的进行直接操作和实验。
这篇文章是关于如何使用Django框架配置MySQL数据库,创建模型实例,并自动或手动创建数据库表,以及对这些表进行操作的详细教程。
84 0
Django学习二:配置mysql,创建model实例,自动创建数据库表,对mysql数据库表已经创建好的进行直接操作和实验。
|
2月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
177 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
2月前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
71 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql