mysql latch_Latch导致MySQL Crash

沃趣科技高级数据库专家  董 红 禹

一、问题概述

最近我们遇到一个MySQL的问题,分析后很有代表意义,特地写出来供大家参考。

出现问题是,数据库先是被置为只读,然后过了一段时间,MySQL直接Crash掉了

发生Crash时MySQL的error日志中打印了以下内容:

----------

SEMAPHORES

----------

OS WAIT ARRAY INFO:reservation count1246555

--Thread140363572082432has waited at row0upd.cc line2354for253.00seconds the semaphore:

X-lock(wait_ex)on RW-latch at0x7fa949340740createdinfile buf0buf.cc line1069

a writer(thread id140363572082432)has reserved itinmode wait exclusive

number of readers1,waiters flag1,lock_word:ffffffffffffffff

Lasttime read lockedinfile btr0sea.cc line931

Lasttime write lockedinfile/export/home/pb2/build/sb_0-17068951-1447697721.44/mysql-5.6.28/storage/innobase/row/row0upd.cc line2354

根据日志中我们可以看到,线程140363572082432要对记录上一个X锁,但是等待0x7fa949340740线程的RW-latch的释放

我们在向下看查询到如下信息(涉及到用户信息 谓词就用xxx代替):

173lockstruct(s),heap size30248,7925rowlock(s),undo log entries7924

MySQLthread id5709783,OS thread handle0x7fa8f0da7700,query id9221303410.23.163.54citicqyh updating

update TB_DEPARTMENT_INFOsetTOTAL_USER=1whereID='ac84f17e-82d3-4519-a1da-0d5a5a835d44'

---TRANSACTION53065242,ACTIVE313sec fetching rows,thread declared insideInnoDB2081

mysql tablesinuse2,locked0

MySQLthread id5428690,OS thread handle0x7fa8f0136700,query id9221306110.23.163.55citicqyhSendingdata

SELECT COUNT(DISTINCT r.user_id)FROM TB_DEPARTMENT_INFO d left join tb_qy_user_department_ref r on r.department_id=d.id WHERE d.org_id='xxx'AND(d.dept_full_name LIKE'xxx%'ord.dept_full_name='xxx

Trx read view will not see trx with id >= xxx, sees < xxx

......还有很多select语句省略

根据上面信息我们去数据库中查看了这些select语句,发现执行计划都是全表扫描。

首先数据库变成了只读,最后数据库crash了,crash输出的信息如下:

----------------------------

ENDOF INNODB MONITOR OUTPUT

============================

InnoDB:###### Diagnostic info printed to the standard error stream

InnoDB:Error:semaphore wait has lasted>600seconds

InnoDB:Weintentionally crash the server,because it appears to be hung.

7fa8f9580700InnoDB:Assertionfailureinthread140363714529024infile srv0srv.cc line1754

InnoDB:Weintentionally generate a memory trap.

InnoDB:Submita detailed bug report to http://bugs.mysql.com.

InnoDB:Ifyougetrepeated assertion failuresorcrashes,even

InnoDB:immediately after the mysqld startup,there may be

InnoDB:corruptionintheInnoDBtablespace.Pleaserefer to

InnoDB:http://dev.mysql.com/doc/refman/5.6/en/forcing-innodb-recovery.html

InnoDB:about forcing recovery.

InnoDB: Error: semaphore wait has lasted > 600 seconds 提示600秒没有响应 数据库选择了Crash 强制重启

从报错信息来看:

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

由于有大量的select语句是全表扫描,一直占用latch没有释放,update迟迟竞争不到RW-latch

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

对应的代码摘录如下:

rw_lock_create(PFS_NOT_INSTRUMENTED,&block->lock,SYNC_LEVEL_VARYING);

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

buf_pool_init_instance()->buf_chunk_init()->buf_block_init()

正是由于这个RW-Latch被长时间占用了,其他的线程一直竞争不到,才导致了这个问题

三、修复建议

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

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

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

适当加大buffer pool instance,每个buffer pool都有自己独立的Latch,避免latch竞争。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值