Latch导致MySQL Crash

问题概述

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

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

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

----------

SEMAPHORES

----------

OS WAIT ARRAY INFO: reservation count 1246555

--Thread 140363572082432 has waited at row0upd.cc line 2354 for 253.00 seconds the semaphore:

X-lock (wait_ex) on RW-latch at 0x7fa949340740 created in file buf0buf.cc line 1069

a writer (thread id 140363572082432) has reserved it in mode wait exclusive

number of readers 1, waiters flag 1, lock_word: ffffffffffffffff

Last time read locked in file btr0sea.cc line 931

Last time write locked in file/export/home/pb2/build/sb_0-17068951-1447697721.44/mysql-5.6.28/storage/innobase/row/row0upd.cc line 2354

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

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

173 lock struct(s), heap size 30248, 7925 row lock(s), undo log entries 7924

MySQL thread id 5709783, OS thread handle 0x7fa8f0da7700, query id 92213034 10.23.163.54 citicqyh updating

update TB_DEPARTMENT_INFO set TOTAL_USER=1 where ID='ac84f17e-82d3-4519-a1da-0d5a5a835d44'

---TRANSACTION 53065242, ACTIVE 313 sec fetching rows, thread declared inside InnoDB 2081

mysql tables in use 2, locked 0

MySQL thread id 5428690, OS thread handle 0x7fa8f0136700, query id 92213061 10.23.163.55 citicqyh Sending data

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%' or d.dept_full_name = 'xxx

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

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

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

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

END OF INNODB MONITOR OUTPUT

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

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

InnoDB: Error: semaphore wait has lasted > 600 seconds

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

7fa8f9580700 InnoDB: Assertion failure in thread 140363714529024 in file srv0srv.cc line 1754

InnoDB: We intentionally generate a memory trap.

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

InnoDB: If you get repeated assertion failures or crashes, even

InnoDB: immediately after the mysqld startup, there may be

InnoDB: corruption in the InnoDB tablespace. Please refer 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竞争。

时间: 2024-12-25 23:13:59

Latch导致MySQL Crash的相关文章

MySQL · 捉虫动态 · ORDER/GROUP BY 导致 mysqld crash

问题描述 表结构如下所示: show create table test\G Table: test Create Table: CREATE TABLE `test` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id2` varchar(50) DEFAULT NULL `id3` varchar(100) DEFAULT NULL `some_text` varchar(200) DEFAULT NULL `name` varchar(

MySQL Crash Errcode: 28 - No space left on device

  一台MySQL服务器突然Crash了,检查进程 ps -ef | grep -i mysql 发现mysqld进程已经没有了, 检查错误日志时发现MySQL确实Crash了.具体如下所示:     注意日志中的时间: 09:49:52 UTC是UTC时间(协调世界时间) , 加上8小时就是东八区的时间17:45:52,日志前段是UTC时间,后面又是系统时间.这个需要注意!   09:49:52 UTC - mysqld got signal 11 ; This could be becaus

oracle中PMON failed to acquire latch导致crash的例子

一朋友公司的OA系统挂了(泛微技术支持说是神马神马),友情帮忙分析一下. 如下是alert log信息: Mon Jun 23 11:28:53 2014 WARNING: inbound connection timed out (ORA-3136) Mon Jun 23 22:00:06 2014 Thread 1 advanced to log sequence 339 (LGWR switch)  Current log# 3 seq# 339 mem# 0: /oradata/redo

semi-sync插件崩溃导致MySQL重启故障详析

本文讲的是semi-sync插件崩溃导致MySQL重启故障详析 导读 semi-sync插件崩溃导致MySQL重启的故障分析全过程~ 作者:刘安 现为爱可生高级测试工程师,拥有丰富的自动测试开发经验:曾先后在文思海辉.Splunk担任测试工程师. 一.起因: 在公司测试MySQL高可用组件时发现一个异常.如下: 停止从库,高可用组件将从库自动启动后,主库发生了重启.然而,正常情况下,主库不应发生重启. 二.环境: 1.OS: CentOS release 6.7 (Final): 2.MySQL

磁盘空间不足导致mysql无法启动的mysql错误

在mysql中查看表提示1030错误: mysql> desc user; ERROR 1030 (HY000): Got error 28 from storage engine 引起这个错误的原因是磁盘空间不足,导致mysql的临时目录空间tmpdir不够. 解决方法是清空linux系统的/tmp目录,或者修改my.cnf中的tmpdir参数,指向具有足够空间的目录. 使用df 查看分区使用情况: [root@jsunsa tmp]# df /tmp Filesystem          

oracle中使用alter system events导致库crash

由于数据库导入大量数据的时候io等待比较高,新的存储无法直接挂过来,考虑使用nfs挂载过来,然后存放redo缓解io压力. 数据库版本信息 SQL> select * from v$version;   BANNER ---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi PL/SQL Rele

Python提示[Errno 32]Broken pipe导致线程crash错误解决方法_python

本文实例讲述了Python提示[Errno 32]Broken pipe导致线程crash错误解决方法.分享给大家供大家参考.具体方法如下: 1. 错误现象ThreadingHTTPServer 实现的 http 服务,如果客户端在服务器返回前,主动断开连接,则服务器端会报 [Errno 32] Broken pipe 错,并导致处理线程 crash. 下面先看个例子,python 版本: 2.7 示例代码 复制代码 代码如下: #!/usr/bin/env python #!coding=ut

千万级记录的Discuz论坛导致MySQL CPU 100%的优化笔记_Mysql

发现此主机运行了几个 Discuz 的论坛程序, Discuz论坛的好几个表也存在着这个问题.于是顺手一并解决,cpu占用再次降下来了. 前几天,一位朋友通过这篇文章找到了我,说他就是运行最新的 discuz 版本,MySQL 占用 CPU 100%,导致系统假死,每天都要重启好几次,花了一个多月的时间一直没有解决,希望我帮忙一下.经过检查,他的这个论坛最重要的几个表中,目前 cdb_members 表,有记录 6.2 万:cdb_threads 表,有记录 11万:cdb_posts表,有记录

unbindService()导致应用Crash的问题

/** * Demo描述: * unbindService()导致应用Crash的问题 * 2014年12月4日10:58:52 * * 今天在改Bug时发现一个问题: * unbindService(mConnection);会导致Crash * * 原因: * 在Activity中绑定Service时候执行的是: * getApplicationContext().bindService(intent, mConnection,BIND_AUTO_CREATE); * 但是在Activity