Latch致使MySQL Crash

做者:沃趣科技数据库专家 董红禹

问题概述数据库

最近咱们遇到一个MySQL的问题,分析后颇有表明意义,特意写出来供你们参考。出现问题是,数据库先是被置为只读,而后过了一段时间,MySQL直接Crash掉了,发生Crash时MySQL的error日志中打印了如下内容:缓存

根据日志中咱们能够看到,线程140363572082432要对记录上一个X锁,可是等待0x7fa949340740线程的RW-Latch的释放。markdown

咱们再向下看查询到以下信息(涉及到用户信息 谓词就用xxx代替):并发

根据上面信息咱们去数据库中查看了这些select语句,发现执行计划都是全表扫描。首先数据库变成了只读,最后数据库Crash了,Crash输出的信息以下:函数

InnoDB: Error: semaphore wait has lasted > 600 seconds 提示600秒没有响应 数据库选择了Crash 强制重启。从报错信息来看:线程

1,update语句须要在记录上面加X锁,可是必须等待RW-Latch的释放日志

2,因为有大量的select语句是全表扫描,一直占用Latch没有释放,update迟迟竞争不到RW-latchblog

3,Innodb 的Diagnostic线程检查到RW-Latch等待超过了600秒尚未返回,认为系统出现了严重问题,因而触发了MySQL服务的Crash。索引

 

进一步分析内存

这里首先须要补充一下Latch的概念:Latch在MySQL中是用于保护高速缓冲区中共享数据的.

举个例子:

当咱们执行select时,数据是缓存在buffer pool中的,多个线程并发访问或者修改这个数据必然须要一个并发控制机制,这个就是Latch

你们知道,数据库要访问的数据都必须先存在缓存中,而缓存通常比磁盘空间要小,数据缓存使用hash表来记录数据页是否在内存中。在Oracle中的并发控制比较精细:首先会对hash桶加latch,并根据hash桶查找对应的数据并加上pin,而后释放Latch。而MySQL相对没有控制得这么精细,对应的RW-Latch在errlog中说的很清楚,该RW-Latch是在buf0buf.cc的1069行建立的 RW-latch at 0x7fa949340740 created in file buf0buf.cc line 1069

对应的代码摘录以下:

跟踪源码,知道这个Latch是MySQL在数据库启动,初始化 innodb_buffer_pool时,将Latch建立好的。对应的函数调用过程:

正是因为这个RW-Latch被长时间占用了,其余的线程一直竞争不到,才致使了这个问题。

 

修复建议

这类问题的发生多数都是由于SQL写的很差,在表上面进行了大量的全表扫描占用了大量的Latch,解决方案就是避免SQL长时间占用Latch:

1,修改select查询避免全表扫描,避免Latch长期被占用。

2,适当的加索引,让select执行更快,也避免一个select锁的数据更少。

3,适当加大buffer pool instance,每一个buffer pool都有本身独立的Latch,避免latch竞争。

相关文章
相关标签/搜索