作者周信静,毕业于浙江大学,目前在CDB/CynosDB数据库内核团队参与TXSQL云数据库内核研发工作,参与了热点行更新以及一系列性能优化工作,并修复了多个MySQL官方bug。

1背景

InnoDB的自适应哈希索引(Adpative Hash Index,以下简称AHI),是一种建立在B树索引结构上的索引结构,目的是为了进一步降低BTree的查询代价。

在B树中搜索一个记录时,需要从根节点下降到叶子结点,同时在每个节点中还需要使用二分查找定位。而AHI对此的改进在于它对BTree索引频繁访问的叶子的行记录建立哈希索引,这样在执行B树查询时,通过AHI就可能能定位到叶子结点上的记录位置,避免B树根节点到叶子结点的下降过程,减少了CPU开销。

由于AHI的构建是一个自适应且动态的过程,需要根据查询负载访问模式的变更、页面的换入和淘汰等情况做AHI对应清理或者重建,所以本质上来说AHI也是一个cache,具体的构建逻辑网络上也有很多文章讲解,不是本文讨论的重点。

本文要讨论的是一个鲜为人知的AHI构建锁冲突问题以及相应优化。

2问题

TXSQL 5.7版本在跑sysbench时,我们观察到一个非常有意思的现象。

实验环境是这样的,2台96-core的机器,分别作为sysbench client和mysql server,我们配置buffer pool大小为200GB,同时生成一张120GB的sysbench table。

如下图所示,我们执行128并发的oltp_read_only负载时,观察到QPS首先有一个上升的坡,这段时间我们发现系统有大量的读IO,正在填充buffer pool,属于正常状态。

然后过了100s时突然出现了一个急剧的下降,在400s后开始系统QPS开始缓慢上升,直到800s后达到峰值。

通过perf工具抓取系统在QPS剧降时间点的状态,结果如下图:

分析堆栈,可以发现,大量CPU花费在在AHI的hash table的锁竞争上。

仔细分析不难发现,这个时候大多数页面基本上还没有建立AHI,然后多个线程同时需要对页面建立AHI索引,而这个构建过程需要对同一个AHI hash table加X锁,因此造成了大量等待。

从QPS变化的角度,可以有如下图所示的分析:

3优化

我们注意到,对于一个BTree索引来说,其AHI构建是在BTree叶子结点定位完毕后发生的,对应调用链如下:

btr_cur_search_to_nth_level→ btr_search_info_update→ btr_search_info_update_slow→ btr_search_build_page_hash_index

在btr_search_info_update_slow中,根据统计信息作出决定,调用btr_search_build_page_hash_index把当前页面的记录加入AHI的hash table,这个过程需要独占hash table的X锁。

既然只能有一个线程对hash table进行修改,那么其他并发构建AHI线程等待这个hash table的X锁是相当不明智的,因为这样block住了查询的关键路径,同时只有一个线程在做这个构建工作。

同时我们又注意到AHI只是一个辅助cache,其实用BTree也是能够正确处理查询的。

那么很自然的,我们可以想到如下的优化方式:

1. 当我们在BTree查询路径上经过分析后决定要对某一页构建AHI索引时,我们首先看一下该BTree所对应的hash table的锁是否被其他线程拿住了写锁;

2. 如果被拿住了写锁,我们取消这次针对页的AHI索引构建任务,等待下次再次访问到该页时再尝试去构建,fallback到普通的BTree查询。

4具体实现

从实现角度来说,其实非常简单:在btr_search_info_update_slow根据统计信息判断要对一页的记录建立AHI索引时,我们加入一个条件判断:如果当前有并发AHI构建线程拿住了hash table的X锁,我们直接返回即可。

代码只有几行,大致如下:

有人可能会担心这样直接跳过会不会影响代码正确性?

答案是否定的,因为我们这里没有清除该页面关于AHI的任何统计信息,只是推迟了构建时机,即推迟到hash table锁冲突不严重的时候再进行。

5效果

应用上述的优化后,我们重新执行上述实验,得到如下的结果图:

其中,红线(开启AHI+Contention Avoidance优化)是我们实现上述优化后结果,经过100s左右的预热后,性能稳定,锁瓶颈消失。

6灵感来源

其实在原始的AHI查询路径上已经有一个类似的优化了:

在btr_cur_search_to_nth_level中执行AHI查询前,如果发现AHI的hash table被其他线程X锁住了,直接fallback到BTree查询。

这里的优化考量是类似的:与其等待AHI的hash table的X锁,不如直接走btree搜索,代价很可能比等待X锁更低,并发度更高。

7总结

该优化目前已经在TXSQL5.7最新版本中上线,将会有效缓解AHI构建的锁竞争问题,可能的场景包括不限于:系统启动、AHI开关刚开启、主备切换时,所有页面都还没有AHI记录,高并发可能导致大量的AHI构建工作。

同时经过我们验证,在官方MySQL的5.7和8.0最新版本中都存在该问题,因此我们也已经将这个优化思路贡献给了官方, https://bugs.mysql.com/bug.php?id=100512 ,目前正在评估,相信不久将合入主线。

手机运维小程序限时免费体验!

手机运维小程序——腾讯云数据库上线啦,从此在手机里可以实现实例信息查看,健康报告接收,慢SQL分析和异常查看等功能,以后回家终于可以不背电脑了!

上云就上腾讯云,双十一全网年度最低价来袭:MySQL高可用版1C2G低至99元/年!更有价值11000元代金券大礼包等你来领取,玩法简单直接,错过又要等一年!

↓↓点击直达双11会场~

腾讯程序员视频号交流沙龙活动预告】

11月21日周六下午2点 深圳

想参与可添加微信:journeylife1900

(备注:视频号)

一个即将写入MySQL源码的官方bug解决之路相关推荐

  1. 转 MySQL源码分析

    看到一个不错的介绍,原址如下: http://software.intel.com/zh-cn/blogs/2010/08/20/mysql0/ MySQL源码分析(0):编译安装及调试 作者: Yu ...

  2. MySQL源码bug#65995

    之前博客<mysql源码中的bug>中描述了在调试源码时的一个bug,已经被MySQL官方确认,感兴趣的可以进行查看.尤其是有源码癖的朋友,在调试过程中可以进行参考. MySQL官方bug ...

  3. Linux安装MySQL(源码安装)

    文章目录 一.下载 二.最小化安装配置 三.MySQL的安装的几种方式 1.MySQL安装方式 2. 三种安装方式的区别 四.MySQL的GLIBC版本安装 1. 上传软件包解压 2. 软件安装 3. ...

  4. MySQL 源码 需要 什么基础_MySQL 基础之 源码 部署

    源码部署 1. 需要先卸载一些软件 centos7 中需要先卸载 mariadb-libs 软件包 # rpm -e --nodeps mariadb-libs 2. 安装依赖包 yum -y ins ...

  5. 怒肝两个月MySQL源码,我总结出这篇2W字的MySQL协议详解(超硬核干货)!!

    写在前面 最近,在开发一个分库分表中间件,由于功能需求,需要分析MySQL协议,发现网上对于MySQL协议分析的文章大部分都过时了,原因是分析的MySQL版本太低了.怎么办呢?于是乎,我便硬着头皮开始 ...

  6. mysql输入错误怎样更正_HotDB MySQL 篇| MySQL 源码系列的补充与更正

    热璞数据库HotDB 产品是基于Mysql 的分布式事务数据库,在上一part的分享中,我们讲到了MySQL源码系类中的2个问题: 1.trigger的event到底怎么回放的,为什么没有主键冲突? ...

  7. mysql long类型_怒肝两个月MySQL源码,我总结出这篇2W字的MySQL协议详解(超硬核干货)!!...

    点击上方蓝色"冰河技术",关注并选择"设为星标" 持之以恒,贵在坚持,每天进步一点点! 作者个人研发的在高并发场景下,提供的简单.稳定.可扩展的延迟消息队列框架 ...

  8. 怎么查看MySQL 源码编译了什么_Mysql 源码编译教程贴

    题外话:这是一篇教程贴,不仅学的是mysql的编译,还是一些编译的知识.我也是一个菜鸟,写一些感悟和心得,有什么问题可以批评指正,谢谢! 如果只是为了安装请移到我的另一篇安装贴: Mysql安装贴 环 ...

  9. Mysql源码编译和调试debug

    下载源码 直接从github 上下载了源码.git 地址:https://github.com/mysql/mysql-server 下载路径如:/work/mysql-server 编译 依赖 ma ...

最新文章

  1. php页面最大执行时间 set_time_limit函数不起作用
  2. java流实例_java流汇总以及使用实例
  3. Element UI格式化日期
  4. python finally语句里面出现异常_Python异常处理中的else和finally
  5. 【并发技术16】线程同步工具Exchanger的使用
  6. 实用收藏Linux命令备忘
  7. Ubuntu系统下允许Apache的mod_rewrite功能
  8. 一文看懂 BDTC 2018:探秘大数据新应用(附 PPT 下载)
  9. 北京信息科技大学计算机专业学科评估,北京信息科技大学学科评估结果排名(第四次):最新完整...
  10. 【每日算法Day 62】LeetCode 815. 公交路线
  11. 连接mongoDB根据ObjectID写入json数据(初步)
  12. Atitit 知识体系概论 attilax著 三大类型 学术型 应用型 职业技术教育 1 附表1、CIP-2000学科群设置情况总表 1 三大层次 分类 学科 专业 2 20个知识大类 2 需
  13. 微信小程序开发学习资料
  14. 51单片机定时器实现钟表(LCD1602显示)
  15. php掷骰子小游戏代码,C语言实现掷骰子游戏代码及解析
  16. 利用群发短信进行精准高效的会员营销
  17. HDU 5811 (拓扑排序 LIS)
  18. SSL: CERTIFICATE_VERIFY_FAILED
  19. 北京理工大学ACM冬季培训课程之C++的应用
  20. linux切换用户时 su-,Linux切换用户(su)

热门文章

  1. Linux改变进程优先级的nice命令
  2. Ipad 日程管理APP使用心得
  3. 关于Html中jsp调用Android中方法无效的一点建议
  4. mysql中varchar与integer的互转
  5. web.xml加载顺序
  6. C++:函数参数不确定时用cstdarg(stdarg.h)
  7. 蓝桥杯 - 序列计数(记忆化搜索)
  8. kicad最小布线宽度默认是多少_你想知道建仓库时叉车通道宽度留多少吗?
  9. Uva536 Tree Recovery二叉树重建(先序和中序确定二叉树,后序输出)
  10. Keras-常用代码