背景

近期线上MySQL 5.7.20集群不定期(多则三周,短则一两天)出现主库mysql crash、触发主从切换问题,堆栈信息如下;

从堆栈信息可以明显看出,在调用 try_acquire_lock_impl 时触发的crash。

分析

在官方Bug库未搜到类似问题,转而从代码库入手,搜到对应的BUG —— 8bc828b982f678d6b57c1853bbe78080c8f84e84

BUG#26502135: MYSQLD SEGFAULTS IN

              MDL_CONTEXT::TRY_ACQUIRE_LOCK_IMPL

ANALYSIS:
=========
Server sometimes exited when multiple threads tried to
acquire and release metadata locks simultaneously (for
example, necessary to access a table). The same problem
could have occurred when new objects were registered/
deregistered in Performance Schema. The problem was caused by a bug in LF_HASH - our lock free
hash implementation which is used by metadata locking
subsystem in 5.7 branch. In 5.5 and 5.6 we only use LF_HASH
in Performance Schema Instrumentation implementation. So
for these versions, the problem was limited to P_S. The problem was in my_lfind() function, which searches for
the specific hash element by going through the elements
list. During this search it loads information about element
checked such as key pointer and hash value into local
variables. Then it confirms that they are not corrupted by
concurrent delete operation (which will set pointer to 0)
by checking if element is still in the list. The latter
check did not take into account that compiler (and
processor) can reorder reads in such a way that load of key
pointer will happen after it, making result of the check
invalid. FIX:
====
This patch fixes the problem by ensuring that no such
reordering can take place. This is achieved by using
my_atomic_loadptr() which contains compiler and processor
memory barriers for the check mentioned above and other
similar places. The default (for non-Windows systems) implementation of
my_atomic*() relies on old __sync intrisics and implements
my_atomic_loadptr() as read-modify operation. To avoid
scalability/performance penalty associated with addition of
my_atomic_loadptr()'s we change the my_atomic*() to use
newer __atomic intrisics when available. This new default
implementation doesn't have such a drawback.

大体含义是:

当多个线程分别同时获取、释放metadata locks时,或者在 Performance Schema 中注册/撤销新的object时,可能会触发该问题,导致 mysql server crash。

该问题是 LF_HASH(Lock-Free Extensible Hash Tables) 的BUG引起的,那么 LF_HASH 用在什么地方呢?

  1. 在5.5、5.6中只用在 Performance Schema Instrumentation 模块。
  2. 在5.7中也用于metadata加锁模块。

问题出在my_lfind() 函数中,该函数针对cursor->prev的判断未考虑CAS,该patch通过使用 my_atomic_loadptr() 解决了该问题:

diff --git a/mysys/lf_hash.c b/mysys/lf_hash.c
index dc019b07bd9..3a3f665a4f1 100644
--- a/mysys/lf_hash.c
+++ b/mysys/lf_hash.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -83,7 +83,8 @@ retry:
do { /* PTR() isn't necessary below, head is a dummy node */
cursor->curr= (LF_SLIST *)(*cursor->prev);
_lf_pin(pins, 1, cursor->curr);
- } while (*cursor->prev != (intptr)cursor->curr && LF_BACKOFF);
+ } while (my_atomic_loadptr((void**)cursor->prev) != cursor->curr &&
+ LF_BACKOFF);
for (;;)
{
if (unlikely(!cursor->curr))
@@ -97,7 +98,7 @@ retry:
cur_hashnr= cursor->curr->hashnr;
cur_key= cursor->curr->key;
cur_keylen= cursor->curr->keylen;
- if (*cursor->prev != (intptr)cursor->curr)
+ if (my_atomic_loadptr((void**)cursor->prev) != cursor->curr)
{
(void)LF_BACKOFF;
goto retry;

解决

查看change log,该问题在5.7.22版本修复的:

A server exit could result from simultaneous attempts by multiple threads to register and deregister metadata Performance Schema objects, or to acquire and release metadata locks. (Bug #26502135)

升级内核版本到5.7.29,之后巡检1个月,该问题未再出现,问题解决。

PS:

篇幅有限,在后续文章中会单独分析 MDL、LF_HASH 源码,敬请关注。


欢迎关注我的微信公众号【MySQL数据库技术】。

知乎 - 数据库技术 专栏: https://zhuanlan.zhihu.com/mysqldb

思否/segmentfault: https://segmentfault.com/u/dbtech

开源中国/oschina: https://my.oschina.net/dbtech

掘金: https://juejin.im/user/5e9d3ed251882538083fed1f/posts

博客园/cnblogs: https://www.cnblogs.com/dbtech

捉虫日记 | MySQL 5.7.20 try_acquire_lock_impl 异常导致mysql crash的更多相关文章

  1. Linux 文件系统引起的云盘文件系统异常导致 MySQL 数据页损坏事故恢复复盘

    事故的起因是因为当我访问某个数据库的某个表的时候,MySQL 立即出现崩溃并且去查看 MySQL 的错误日志出现类似信息 --09T05::.232564Z [ERROR] InnoDB: Space ...

  2. 记录一次更改服务器名称导致mysql 不能正常登录、启动

    由于客户要求更改服务器的名称,以便区分多台服务器:修改前mysql 能正常登录,但是修改后,登录时报错: Enter password: ERROR 1524 (HY000): Plugin '*C6 ...

  3. 捉虫记(四)线程安全导致的HighCpu

    一个朋友QQ群里说网站启动后会cpu很高,想要帮忙看一下dump. 1.打开windbg加载dump文件后第一个命令lmf,这个命令显示加载的dll以及路径,这样子可以找个dll来帮忙加载sos,(额 ...

  4. [MySQL Reference Manual] 20 分区

    20 分区 20 分区 20.1 MySQL的分区概述 20.2 分区类型 20.2.1 RANGE分区 20.2.2 LIST分区 20.2.3 COLUMNS分区 20.2.3.1 RANGE C ...

  5. mysql 5.6.20的安装、配置服务、设置编码格式

    一.安装 安装环境        系统:Window 32        版本:Mysql 5.6.20 1. 首先从官网上http://dev.mysql.com/downloads/mysql/ ...

  6. win 2012 安装mysql 5.7.20 及报错 This application requires Visual Studio 2013 Redistributable. Please install the Redistributable then run this installer again 的解决办法

    本文地址:http://www.cnblogs.com/jying/p/7764147.html    转载请注明出处. 安装过程其实挺简单,基本上下一步下一步,可以参考我的另一篇mysql安装文章: ...

  7. Windows 64 位 mysql 5.7.20 安装教程

    mysql 5.7以上版本包解压中没有data目录和my-default.ini和my.ini文件以及服务无法启动的解决办法以及修改初始密码的方法 mysql官网下载地址:https://dev.my ...

  8. Windows 下 MySql 5.7.20安装及data和my.ini文件的配置(转)

    Windows 下 MySql 5.7.20安装及data和my.ini文件的配置     本文通过图文并茂的形式给大家介绍了MySql 5.7.20安装及data和my.ini文件的配置方法. my ...

  9. CentOS 7.4 使用源码包编译安装MySQL 5.7.20

    使用yum安装的MySQL一般版本比较旧,但是运行稳定.如果想要尝试最新的功能或者需要指定特殊的功能的话,就需要手工进行编译安装了. 一.下载安装包 (一).先下载MySQL源码,网址为:https: ...

随机推荐

  1. Netty实现对Websocket的支持

    一.WebSocket的简介及优势 WebSocket 是一种网络通信协议.RFC6455 定义了它的通信标准.WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的 ...

  2. 看看PHP迭代器的内部执行过程(转)

      1 class myIterator implements Iterator { 2 private $position = 0; 3 private $array = array( 4 &quo ...

  3. 跨域解决之JSONP和CORS的详细介绍

    JSONP跨域和CORS跨域 什么是跨域? 跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制! 同源策略 同源策略:域名.协议.端口均相同. 浏览器执行Jav ...

  4. openjudge走迷宫(DFS)

    题目: 描述 一个迷宫由R行C列格子组成,有的格子里有障碍物,不能走:有的格子是空地,可以走. 给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到).只能在水平方向或垂直方向走,不 ...

  5. FastTunnel-开源内网穿透框架

    FastTunnel - 打造人人都能搭建的内网穿透工具 FastTunnel是用.net core开发的一款跨平台内网穿透工具,它可以实现将内网服务暴露到公网供自己或任何人访问. 与其他穿透工具不同 ...

  6. python pip install matplotlib安装模块

    python pip install matplotlib安装模块,可附带安装相关的模块 程序运行提示: from . import _imaging as coreImportError: DLL ...

  7. Linux上生产环境源码方式安装配置postgresql12

    1.Linux上源码方式安装postgresql12 01.准备操作系统环境 echo "192.168.1.61 tsepg61" >> /etc/hosts mou ...

  8. 二进制方式安装 k8s

    推荐个好用的安装k8s的工具 https://github.com/easzlab/kubeasz 该工具基于二进制方式部署 k8s, 利用 ansible-playbook 实现自动化    1.1 ...

  9. CentOS下配置Nginx实现动静分离实例

    测试环境: CentOS Linux release 7.6 PHP 7.2.32 两台服务器:192.168.1.109(Nginx),192.168.1.118(Apache) 1. 安装配置19 ...

  10. Linux CentOS 7 安装配置vsftp

    学习Linux时间不长,首次安装了vsftp,按照网上的各种帖子尝试配置,不过都没打到预期,不是被拒绝连接,就是连接超时,总之就是各种问题啊.当然了,不是别人配置的不对,而是自己不是太懂Linux,选 ...