位置: 编程技术 - 正文

MySQL redo死锁问题排查及解决过程分析(mysql死锁的情况)

编辑:rootadmin

推荐整理分享MySQL redo死锁问题排查及解决过程分析(mysql死锁的情况),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:mysql的死锁,mysql的死锁,mysql解决死锁的4种基本方法,mysql死锁的原因及解决方法,mysql死锁解决方案,mysql死锁问题,mysql死锁案例,mysql死锁案例,内容如对您有帮助,希望把文章链接给更多的朋友!

问题背景

周一上班,首先向同事了解了一下上周的测试情况,被告知在多实例场景下 MySQL Server hang 住,无法测试下去,原生版本不存在这个问题,而新版本上出现了这个问题,不禁心头一颤,心中不禁感到奇怪,还好现场环境还在,为排查问题提供了一个好的环境,随即便投入到紧张的问题排查过程当中。问题实例表现如下:

首先,通过 pstack 工具获取当前问题实例的堆栈信息以便后面具体线程的查找 & 问题线程的定位:

使用 pt-pmp 工具统计 hang.info 中的进程信息,如下:

问题分析

从堆栈上可以看出,有这样几类线程:

等待进入 INNODB engine 层的用户线程,测试环境中 innodb_thread_concurrency=, 当 INNODB 层中的活跃线程数目大于此值时则需要排队,所以会有大量的排队线程,这个参数的影响&作用本身就是一篇很不错的文章,由于篇幅有限,在此不做扩展,感兴趣者可以参考官方文档:. InnoDB Startup Options and System Variables;操作过程中需要写 redo log 的后台线程,主要包括 page cleaner 线程、异步 io threads等;正在读取Page页面的 purge 线程 & 操作 change buffer 的 master thread;大量的需要写 redo log 的用户线程。从以上的分类不难看出,所有需要写 redo log 的线程都在等待 log_sys->mutex,那么这个保护 redo log buffer 的 mutex 被究竟被哪个线程获取了呢,因此,我们可以顺着这个线索进行问题排查,需要解决以下问题:

问题一:哪个线程获取了 log_sys->mutex ?问题二:获取 log_sys->mutex 的线程为什么没有继续执行下去,是在等其它锁还是其它原因?问题三:如果不是硬件问题,整个资源竟争的过程是如何的?

1.问题一:由表及里

在查找 log_sys->mutex 所属线程情况时,有两点可以帮助我们快速的定位到这个线程:

由于 log_sys->mutex 同时只能被同一个线程获得,所以在 pt-pmp 的信息输出中就可以排除线程数目大于1的线程;此线程既然已经获取了 log_sys->mutex, 那就应该还是在写日志的过程中,因此重点可以查看写日志的逻辑,即包括:mtr_log_reserve_and_write 或 log_write_up_to 的堆栈。顺着上面的思路很快的从 pstack 中找到了以下线程:

这里我们简单介绍一下MySQL写 redo log 的过程(省略undo & buffer pool 部分),当对数据进行修改时,MySQL 会首先对针对操作类型记录不同的 redo 日志,主要过程是:

记录操作前的数据,根据不同的类型生成不同的 redo 日志,redo 的类型可以参考文件:src/storage/innobase/include/mtr0mtr.h 记录操作之后的数据,对于不同的类型会包含不同的内容,具体可以参考函数:recv_parse_or_apply_log_rec_body(); 写日志到 redo buffer,并将此次涉及到脏页的数据加入到 buffer_pool 的 flush list 链表中; 根据 innodb_flush_log_at_trx_commit 的值来判断在commit 的时候是否进行 sync 操作。

上面的堆栈则是写Redo后将脏页加到 flush list 过程中时 hang 住了,即此线程在获取了 log_sys->mutex 后,在获取 log_sys->log_flush_order_mutex 的过程中 hang 住了,而此时有大量的线程在等待该线程释放log_sys->mutex锁,问题一 已经有了答案,那么log_sys->log_flush_order_mutex 是个什么东东,它又被哪个占用了呢?

说明:

1、MySQL 的 buffer pool 维护了一个有序的脏页链表 (flush list according LSN order),这样在做 checkpoint & log_free_check 的过程中可以很快的定位到 redo log 需要推进的位置,在将脏页加入; 2、flush list 过程中需要对其上锁以保证 flush list 中 LSN 的有序性, 但是如果使用 log_sys->mutex,在并发量大的时候则会造成 log_sys->mutex 的 contention,进而引起性能问题,因此添加了另外一个 mutex 来保护脏页按 LSN 的有序性,代码说明如下:

2.问题二:弹尽粮绝

在问题一的排查过程中我们确定了 log_sys->mutex 的所属线程, 这个线程在获得 log_sys->log_flush_order_mutex 的过程中 hang 住了,因此线程堆栈可以分以为下几类:

Thread , 获得 log_sys->mutex, 等待获取 log_sys->log_flush_order_mutex 以把脏页加入到 buffer_pool 的 flush list中; 需要获得 log_sys->mutex 以写日志或者读取日志信息的线程; 未知线程获得 log_sys->log_flush_order_mutex,在做其它事情的时候被 hang 住。

因此,问题的关键是找到哪个线程获取了 log_sys->log_flush_order_mutex。

为了找到相关的线程做了以下操作:

查找获取 log_sys->log_flush_order_mutex 的地方;

MySQL redo死锁问题排查及解决过程分析(mysql死锁的情况)

结合现有 pstack 中的线程信息,仔细查看上述查找结果中的相关代码,发现基本没有线程获得 log_sys->log_flush_order_mutex; gdb 进入 MySQL Server, 将 log_sys->log_flush_order_mutex 打印出来,发现 {waiters=1; lock_word= 0}!!!,即 Thread 在等待一个空闲的 mutex,而这个Mutex也确实被等待,由于我们的版本为 Release 版本,所以很多有用的信息没有办法得到,而若用 debug 版本跑则很难重现问题,log_flush_order_mutex 的定义如下:

由以上的分析可以得出 问题二 的答案:

只有两个线程和log_sys->log_flush_order_mutex有关,其中一个是 Thread 线程, 另外一个则是最近一次调用 log_flush_order_mutex_exit() 的线程; 现有线程中某个线程在释放log_sys->log_flush_order_mutex的过程中没有唤醒 Thread ,导致Thread hang 并造成其它线程不能获得 log_sys->mutex,进而造成实例不可用; log_sys->log_flush_order_mutex 没有被任何线程获得。 3.问题三:绝处逢生

由问题二的分析过程可知 log_sys->log_flush_order_mutex 没有被任何线程获得,可是为什么 Thread 没有被唤醒呢,信号丢失还是程序问题?如果是信号丢失,为什么可以稳定复现?官方的bug list 列表中是没有类似的 Bug的,搜了一下社区,发现可用信息很少,这个时候分析好像陷入了死胡同,心里压力开始无形中变大……好像没有办法,但是任何问题都是有原因的,找到了原因,也就是有解的了……再一次将注意力移到了 Thread 的堆栈中,然后查看了函数:

由问题二的分析过程可以得出某线程在 log_flush_order_mutex_exit 的退出过程没有将 Thread 唤醒,那么就顺着这个函数找,看它如何唤醒其它本程的,在没有办法的时候也只有这样一步一步的分析代码,希望有些收获,随着函数调用的不断深入,将目光定在了 mutex_exit_func 上, 函数中的注释引起了我的注意:

从上面的注释中可以得到两点信息:

由于 memory barrier 的存在,mutex_get_waiters & mutex_reset_lock_word 的调用顺序可能与执行顺序相反,这种情况下会引起 hang 问题; 专门写了一个函数 sync_arr_wake_threads_if_sema_free() 来解决上述问题。

由上面的注释可以看到,并不是信号丢失,而是多线程 memory barrier 的存在可能会造成指令执行的顺序的异常,这种问题确定存在,但既然有sync_arr_wake_threads_if_sema_free() 规避这个问题,为什么还会存在 hang 呢?有了这个线索,瞬间感觉有了些盼头……经过查找 sync_arr_wake_threads_if_sema_free 只在 srv_error_monitor_thread 有调用,这个线程是专门对 MySQL 内部异常情况进行监控并打印出 error 信息的线程,臭名昭著的 S 自杀案也是它的杰作, 那么问题来了:

机器周末都在 hang 着,为什么没有检测到异常并 abort 呢? 既然 sync_arr_wake_threads_if_sema_free 可以唤醒,为什么没有唤醒呢?

顺着这个思路,查看了pstack 中 srv_error_monitor_thread 的堆栈,可以发现此线程在获取 log_sys->mutex 的时候hang 住了,因此无法执行sync_arr_wake_threads_if_sema_free() & 常归的异常检查,正好回答了上面的问题,详细堆栈如下:

经过上面的分析问题越来越明朗了,过程可以简单的归结为:

Thread 获得 log_sys->mutex, 但是在等待 log_sys->log_flush_order_mutex 的过程中没有被唤醒; Thread XXX 在释放 log_sys->log_flush_order_mutex 的过程中出现了 memory barrier 问题,没有唤醒 Thread ; Thread 获得 log_sys->mutex 时被 hang 住,导致无法执行 sync_arr_wake_threads_if_sema_free(), 导致了整个实例的 hang 住; Thread 需要获得 Thread 的 log_sys->mutex, 而 Thread 需要被 Thread 唤醒才会释放 log_sys->mutex;

结合 log_sys->log_flush_order_mutex 的状态信息,实例 hang 住的整个过程如下:

关于 Memory barrier 的介绍可以参考 :

Memory

问题解决

既然知道了问题产生的原因,那么问题也就可以顺利解决了,有两种方法:

直接移除 log_get_lsn 在此处的判断,本身就是开发人员加的一些判断信息,为了定位 LSN 的异常而写的,用到的时候也Crash了,用处不大; 保留判断,将 log_get_lsn 修改为 log_peek_lsn, 后者会首先进行 try_lock,当发现上锁失败的时候会直接返回,而不进行判断,这种方法较优雅些; 经过修改之后的版本在测试过程中没有没有再复现此问题。

问题扩展

虽然问题解决了,但官方版本中肯定存在着这个问题,为什么 buglist 没有找到相关信息呢,于是在查看了最新代码,发现这个问题已经修复,修复方法为上面列的第二种方法,详细的 commit message 信息如下:

bug影响范围:MySQL 5.6. 及之前的版本都有此问题。

MySQL 自动清理binlog日志的方法 说明:开启MySQLbinlog日志的服务器,如果不设置自动清理日志,默认binlog日志一直保留着,时间一长,服务器磁盘空间被binlog日志占满,导致MySQL数据库

mysql出现ERROR (HY)的解决方法 ERROR(HY):Yourpassworddoesnotsatisfythecurrentpolicyrequirements,出现这个问题怎么办?不用着急,下面给出答案。为了加强安全性,MySQL5.7为root用户随机生成了

php mysql访问数据库的步骤详解 php访问mysql数据库的步骤官方说5.5开始就废弃mysql_query()这块东西很多,当然常用的就几个还是看手册吧。这里简单记录一下。在我失忆之后可以找回一

标签: mysql死锁的情况

本文链接地址:https://www.jiuchutong.com/biancheng/348938.html 转载请保留说明!

上一篇:微信公众平台开发 数据库操作(微信公众平台在哪里打开)

下一篇:MySQL 自动清理binlog日志的方法(mysql自动清理数据)

  • 只报个税不交社保有什么税务风险
  • 收入准则范围内
  • 标书费没有发票收据可以入帐吗
  • 货款不入公司账户属什么行为
  • 金税盘清卡怎么统计税额
  • 无形资产处置收益计入
  • 重型开输机属于固定资产什么类别
  • 企业内部控制调查问卷
  • 应收票据和应收账款的区别举例
  • 房产税从租计征的税率是12%还是4%
  • 价外收取的返还利润是什么意思
  • 转租的门面怎么办营业执照
  • 商贸公司购买的手提袋怎么入账
  • 进口内销是什么意思
  • 股东打入公户的钱怎么做账
  • 月末结转所有收入类账户
  • 个税公司承担怎么做账计入其他应收款怎么平账
  • 兼营免税业务,如何才能享受免税的优惠政策?
  • 投资者减除费用可以填0吗
  • 残障人士能享受的税收优惠
  • 不动产增值税总结
  • 医疗服务收入占比分析
  • 没给顾客发票需要罚款吗
  • 购买土地建房出售怎么做账
  • 稽查补缴增值税怎样做账
  • 酒店客房收入怎么算
  • 股权筹资的概念
  • window10拖动窗口的手势
  • 公司聚餐计入什么会计科目
  • ramaint.exe - ramaint是什么进程 有什么用
  • 主营业务成本如何算
  • mac苹果系统怎么用
  • 建筑工程简易计税可以抵扣吗
  • Yii2隐藏frontend/web和backend/web的方法
  • mstore.exe - mstore是什么进程 有什么用
  • PHP:mb_decode_numericentity()的用法_mbstring函数
  • 补充医疗保险是六险吗
  • 收到银行本票的账务处理
  • 受托代销商品会计分录受托方
  • 小微企业所得税税收优惠政策2023年
  • laravel入门与实战
  • php生成证书图片
  • pytorch自动编码器
  • inature前沿
  • 基于SadTalker的AI主播,Stable Diffusion也可用
  • php实现批量删除
  • 个人所得税如何查询
  • 保险费的增值税税率
  • 收取水电费计入什么科目
  • 已抵扣的发票冲红会计分录
  • 房租没发票怎么入账
  • 接受捐赠的增值税可以抵扣吗
  • 会计一般什么时候忙
  • 什么样的纳税人属于小规模纳税人
  • 银行存款利息如何计算
  • 小规模增值税减按1%缴纳,如何申报
  • 建筑材料资源税
  • 新旧会计准则的科目区别
  • 预付账款借方如何结转
  • 独立核算和非独立核算哪个好
  • 计提风险准备金是什么意思
  • windows9怎么截图
  • 苹果15手机价格和图片颜色
  • u盘安装win7系统教程图解
  • javascript中的数组可以存放任何类型的数据
  • Bullet(Cocos2dx)之交叉编译Android,集成到cocos2dx3.x
  • 安卓中的多线程
  • javascript的核心语言对象包括
  • javascript制作
  • 百度关键字搜索员是干嘛的
  • javascript高级程序设计电子书
  • 基于nodejs的框架
  • jquery 表单
  • linux的python
  • python自动化部署oracle csdn
  • 房产税纳税义务终止
  • 小规模纳税人开专票需要交税吗
  • 发票 报销流程
  • 增值税普票十万怎么开
  • 跨市变更税务登记要多久
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设