MySQL:修改系统时钟会导致数据库hang住吗?

2023-10-19 17:30

本文主要是介绍MySQL:修改系统时钟会导致数据库hang住吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

水平有限,有误请谅解

约定:

  • page rwlock:控制page frame本生的读写锁,这个通常再进行对page的读取和修改的时候会涉及到,比如对page的修改需要上x类型的锁。

  • page mutex:主要控制page的io状态等信息的mutex,本文不涉及。

  • MTR:最小日志单元,对于写操作而言,其中包含了redo信息和page rwlock信息,MTR提交的时候会释放page rw lock,并且将本次MTR的redo信息写到redo buffer。

一、问题展示

最近遇到2次这个比较奇葩得问题,一次是8.0.16/一次是8.0.18,主要是信号量监控线程发现读写锁超时自杀重启数据库。问题现象如下:

  1. 读写锁超时crash

主要的等待在如下的rwlock上,如下:

  • 某线程 --Thread 140571742508800 has waited at buf0flu.cc line 1357 for 830 seconds the semaphore

  • 某线程 --Thread 140579717510912 has waited at btr0pcur.h line 656 for 613 seconds the semaphore

当然不是上面这么少,肯定很多,但是类型大概就是这两种。

  1. 日志系统完全停止

这个问题主要在于整个信号量超时期间,从第一个信息输出到最后一个信息输出都不会变比如如下:

Log sequence number          20600471237
Log buffer assigned up to    20600471237
Log buffer completed up to   20600471237
Log written up to            20600471237
Log flushed up to            20600471237
Added dirty pages up to      20598368792
Pages flushed up to          20598368792
Last checkpoint at           20598368792
...
Pending writes: LRU 0, flush list 2, single page 0

这里伴随着刷盘IO的问题。

二、初次分析

  1. 这些堵塞的线程到底是什么,又堵塞在什么读写锁上

一般来讲我们读写锁一般都说文中开头说的page rwlock。

--Thread 140571742508800 has waited at buf0flu.cc line 1357 for 830 seconds the semaphore 这种类型的实际上一看等待点就知道这玩意是clean线程,稍微翻一下代码就知道这里是在做flush list的刷盘。通常刷盘的时候会获取page rwlock(sx类型)

--Thread 140579717510912 has waited at btr0pcur.h line 656 for 613 seconds the semaphore 这种类型的实际上就是正常的用户session,在对page进行访问或者修改的时候需要page rwlock(x/s类型)。

那么我们的redo日志系统卡住前后的几个lsn代表什么意思呢?如下:

Log written up to            20600471237     
Log flushed up to            20600471237
Added dirty pages up to      20598368792
Pages flushed up to          20598368792
  • Log written up to :这实际上是log writer线程写入到的redo的lsn位,在log_files_write_buffer函数内部更改,当然log writer是不断地进行recent write数组,然后不断地写入到redo。对应log.write_lsn.load()。

  • Log flushed up to:这实际上是log flusher线程刷盘到的redo的lsn位点,在log_flush_lown函数内部更改。对应 log.flushed_to_disk_lsn.load()。

  • Added dirty pages up to:这实际上在8.0.16/8.0.18是由log closer线程更新的,但是8.0.22对log closer线程做了删除,直接由用户线程自己负责。主要是查看推进的recent close数组的位点。对应就是log.recent_closed.tail()变量。而recent close数组作为clean线程和用户线程(8.0.22之前还有log closer线程)之间同步信息,我们很容易发现clean线程在根据recent close数组推进的结果进行刷脏参考函数page_cleaner_flush_pages_recommendation的开头。

  • Pages flushed up to:这实际上又log checkpoint线程更新,在进行进行检查点之前,会进行可以进行检查点的位置,那么这个位置必须是已经写了脏数据的位点,从计算的方式来看主要是应该是获取各个buffer pool上flush list最老的那个page,那么就是当前脏叶刷新的位点,但是有一些特别的计算函数log_compute_available_for_checkpoint_lsn

我们看到一个特别的现象就是Log flushed up to - Added dirty pages up to 大概不就是2M的空间,我印象中recent_closed数组的最大值就是2M,因此是不是说明recent_closed已经满了,但是log closer线程不做推进了。如果是这种情况也很容模拟,我只需要用gdb的挂起线程的功能,将log closer挂起即可,我随后进行了测试确实现象一模一样。这也很容易理解,如果redo刷盘功能停止,那么MTR的提交必然会受到堵塞,而我们page rwlock在MTR提交的时候释放,所以hang住很容易理解。那么是不是有BUG呢,当然版本比较老,如果有这个问题应该会由爆出来,因此用 log closer BUG mysql为关键字好像并没有找到相关的BUG。

三、再次分析

前面考虑的是recent_closed数组已满的情况,还会不会是recent_closed数组根本就是空的呢,我随后查看log closer问题时候的stack,发现是正常的等待状态,因此recent_closed数组为空的可能性就很大了。然后稍微看看MTR提交的时候关于recent_closed的更改前会判断recent_closed是否有足够的空间,如果这里出现问题,那么后面的recent_closed数组更新和将脏块挂入到flush list就不会做,那么log_closer线程自然会在推进完最后一次recent_closed数组后,因为无事可做而挂起。代码很简单就是下面这点:7edf9c957154c256c3ddbee0eca73112.png

然后呢我以log_wait_for_space_in_log_recent_closed函数为关键字寻找BUG,真还有如下:

  • https://bugs.mysql.com/bug.php?id=96615

看提交者的描述这种问题就会导致 log closer无事可做而挂起,原因是在等待空闲recent_closed数组空间的时候用的不是原子时钟,如果修改系统时间可能会出现这个问题。官方也没说修复这个问题,最后的回复如下:0db26432e843a444a174c4dbe6efca19.png

看来真的不能随便更改系统时间,非原子时钟问题,可能导致某些该唤醒的不能唤醒。这回导致系统直接hang住。

可能这样描述比较难理解,我用一个图来表示吧,因为涉及的东西比较多。注意了,这里不是说的事务提交,是MTR的提交,实际上我们的redo是一直在做写入操作的,MTR的提交和后台线程之间是异步的。但是一旦涉及到事务提交,那么双1的情况下就必须要保证redo 刷盘,那么到底异步的这些操作到底刷盘没有,那就需要去额外的确认操作,如果还没刷盘那就等,这个由我们的log_writer_notifier/log_flush_notifier线程介入,却确认和反馈给用户线程。但是这个BUG里不涉及,红色部分就是问题所在点,

a62aeb91ccff99f9e08bccfe60d2e07c.png
未命名文件.png

这篇关于MySQL:修改系统时钟会导致数据库hang住吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/241277

相关文章

MySQL 8 中的一个强大功能 JSON_TABLE示例详解

《MySQL8中的一个强大功能JSON_TABLE示例详解》JSON_TABLE是MySQL8中引入的一个强大功能,它允许用户将JSON数据转换为关系表格式,从而可以更方便地在SQL查询中处理J... 目录基本语法示例示例查询解释应用场景不适用场景1. ‌jsON 数据结构过于复杂或动态变化‌2. ‌性能要

MySQL字符串常用函数详解

《MySQL字符串常用函数详解》本文给大家介绍MySQL字符串常用函数,本文结合实例代码给大家介绍的非常详细,对大家学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql字符串常用函数一、获取二、大小写转换三、拼接四、截取五、比较、反转、替换六、去空白、填充MySQL字符串常用函数一、

MySQL中比较运算符的具体使用

《MySQL中比较运算符的具体使用》本文介绍了SQL中常用的符号类型和非符号类型运算符,符号类型运算符包括等于(=)、安全等于(=)、不等于(/!=)、大小比较(,=,,=)等,感兴趣的可以了解一下... 目录符号类型运算符1. 等于运算符=2. 安全等于运算符<=>3. 不等于运算符<>或!=4. 小于运

虚拟机Centos7安装MySQL数据库实践

《虚拟机Centos7安装MySQL数据库实践》用户分享在虚拟机安装MySQL的全过程及常见问题解决方案,包括处理GPG密钥、修改密码策略、配置远程访问权限及防火墙设置,最终通过关闭防火墙和停止Net... 目录安装mysql数据库下载wget命令下载MySQL安装包安装MySQL安装MySQL服务安装完成

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

Zabbix在MySQL性能监控方面的运用及最佳实践记录

《Zabbix在MySQL性能监控方面的运用及最佳实践记录》Zabbix通过自定义脚本和内置模板监控MySQL核心指标(连接、查询、资源、复制),支持自动发现多实例及告警通知,结合可视化仪表盘,可有效... 目录一、核心监控指标及配置1. 关键监控指标示例2. 配置方法二、自动发现与多实例管理1. 实践步骤

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

MySQL 主从复制部署及验证(示例详解)

《MySQL主从复制部署及验证(示例详解)》本文介绍MySQL主从复制部署步骤及学校管理数据库创建脚本,包含表结构设计、示例数据插入和查询语句,用于验证主从同步功能,感兴趣的朋友一起看看吧... 目录mysql 主从复制部署指南部署步骤1.环境准备2. 主服务器配置3. 创建复制用户4. 获取主服务器状态5

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种