【原创】记一次MySQL大表高并发写入引发CPU飙升的排障过程
目录
一.故障现象... 1
二.初步分析... 2
三.排障过程... 2
1.排查是否QPS或insert并发请求上升导致问题发生... 2
2.排查是否锁资源等待或block导致了insert变慢... 3
3.排查是否表上无用索引导致的写入时间较长... 5
4、人工抓取perf,排查CPU上升期间的资源消耗... 5
5、疑似触发MySQL BUG,进一步分析... 6
四.优化过程... 8
1.初步优化方案... 8
2.删除一批无用索引,将服务器内存升级到80G.. 9
3.未达预期,还需继续优化... 11
4.热表索引分析... 11
5.随机GUID建立索引的性能测试... 13
6.热表索引优化方案... 14
7.前缀索引的性能测试... 14
8.删除热表上非顺序的二级索引... 16
五.最终优化方案... 17
六.总结... 18
一.故障现象
有台生产服务器间歇性CPU飙升,出现大量insert语句的慢查询,相关业务的响应时间随之大幅上升

二.初步分析
从监控报告来看,这台服务器的负载并不高

消耗时间高的SQL是insert系列语句
三.排障过程
1.排查是否QPS或insert并发请求上升导致问题发生
排查并发请求没并有突然升高,反而在问题时间段先大幅下降再小幅上升,这个现象说明MySQL在问题时间段的处理能力发生了下降

表的insert并发频率并没有大的波动
2.排查是否锁资源等待或block导致了insert变慢
以一句慢查询insert into为例,查询SQL执行的明细记录,这句SQL的执行时间在异常时间点达到12秒,对应locktime只有63微秒,排除了表锁等待,排查问题发生过程中,rowlock相关指标没有大幅上升,排除rowlock等待,也没有明显的block产生,正常执行时<3毫秒。
3.排查是否表上无用索引导致的写入时间较长
我们都知道表上大量的无用索引不仅浪费存储空间,也会增加数据写入的成本,因此在测试环境新建了相同的表,保留索引不变,测试索引维护成本的消耗
看到这句insert into正常执行时的各阶段的消耗,总体执行时间不到2ms

4、人工抓取perf,排查CPU上升期间的资源消耗
参考命令如下,
注意:下面命令在生产上执行时有较低概率会导致服务器hang死
#生成mysql进程10秒内资源消耗采样报告
sudo perf record -p `pidof mysqld` -g -o /tmp/perf.data sleep 10
#查看报告
sudo perf report -i /tmp/perf.data

CPU资源消耗占比较高的是ibuf_get_volume_buffered_count_func函数,它主要有2个功能,一是统计change buffer中对于同一page ,buffer了多少空间,二是在准备插入类型为IBUF_OP_DELETE的操作缓存时,会预估在apply完该page上所有的ibuf entry后还剩下多少记录。
5、疑似触发MySQL BUG,进一步分析
通过网上搜索,了解到有相关的BUG
该BUG的链接:https://bugs.mysql.com/bug.php?id=77827
下面是BUG描述


MySQL对每个表对象独立分配rw lock,当开启change buffer时,Innodb会频繁的创建dummy table(一种用于线程私有的简单的索引结构),这种dummy index事实上无需使用states_latch,因为他是线程私有的;但mysql没有做区分,在创建rw lock时,会加全局锁rw_lock_list_mutex来维护全局读写锁链表rw_lock_list。
也看到Ali关于这个问题的分析,同时也发现几个关联的BUG,直到MySQL5.7.6版本,问题才完全修复

四.优化过程
1.初步优化方案
1、 从以上分析来看,这个问题的产生与业务大量的二级索引频繁更新是有关系的,目前DB下共有5094个索引。因此我们决定先删除大量无用的索引,看效果是否明显
2、还有个导致问题的原因是内存远小于数据集,计划将innodb_buffer_pool_size从64G扩充到70G-90G之间
2.删除一批无用索引,将服务器内存升级到80G
将这台服务器的内存升到80G后,对比了这个集群昨天和今天的运行情况。
总的来看,增加内存后,CPU波动有所缓解,CPU的峰值和高消耗持续的时间有所降低,运行时的并发线程数也有降低,但问题并没有根本解决。
这台服务器(QPS约4000)的change buffer使用情况,缓存最大时达到23G(说明有大量的二级索引在写入时需要加入缓存进行合并),但是按照目前80G的buffer pool,change buffer的最大值只有20G,仍有瓶颈

对比另外写入频繁的(QPS约9000)一台服务器change buffer的使用情况,最大只有256K

3.未达预期,还需继续优化
评估下来后,需要继续删除热表的索引,下面对热表的索引情况做了进一步分析
4.热表索引分析
分析DB下热表的时候发现每次CPU飙升,逻辑IO消耗时间较长的表排名TOP 2都是固定的两张表,约占了所有表逻辑IO消耗时间的80%。
这两张表有什么特征会影响到逻辑IO的消耗时间,下面其中一张表为例
表结构中有一个row_key的字段,和开发确认,这个字段存储的是随机的GUID值,对应这个字段上建立了一个索引idx_row_key。
我们知道Innodb的聚集索引和二级索引都是一颗B+树,row_key字段建立索引,在插入数据维护索引时,以row_key值的大小做为页和记录的排序规则,随着大量并发随机GUID值的插入,
为了保持B+树的平衡,新插入的数据可能会带来大量的页拆分的操作,这时change buffer起到了关键的优化作用,将二级索引的操作缓存下来,并进行操作合并,减少二级索引的随机IO。
这两个表的容量使用情况,记录数达到3亿条,二级索引占用了较多的容量
5.随机GUID建立索引的性能测试
在测试环境中模拟类似的场景,使用sysbench并发256线程进行压测


结论:
1、 随着表的记录数的增多,当达到千万级以上的记录数时,随机GUID字段上的二级索引维护开销很明显,对插入性能的影响逐渐增大(从开始的30K的QPS下降到约3K)。
2、 删除GUID字段的二级索引后,QPS处理能力大幅上升,恢复到40K的QPS
6.热表索引优化方案
1、 从索引使用统计来看这张表上的idx_row_key索引实际并没有使用过,如果能直接删除,优化效果预计会比较明显
2、 如果业务逻辑上row_key的索引确实需要,折中的办法可以尝试创建前缀索引

对随机GUID值的前8个字符创建索引,这样只在B+树中存储字符串的前几个字符的编码,能节约一部分空间,减少字符串的比较时间,在一定程度上缓解排序和页拆分的问题,语法如下:
ALTER TABLE table1 ADD INDEX idx_row_key_prefix(row_key(8));
3、 业务上修改逻辑,将完全随机的GUID生成规则改为顺序的GUID生成规则
7.前缀索引的性能测试
下面测试表的数据约9000W,建立了两个随机GUID字段的前11个字符的前缀索引,QPS稳定在约10K左右。



8.删除热表上非顺序的二级索引
观察一天下来,CPU高消耗的问题基本消除。

当前change buffer的使用有较大幅度的减少,与删除索引前相比降低了约74%

五.最终优化方案
将两张大表改造为以时间字段为分区函数的分区表,分区表只保留最近30天的数据,改造完成后,从change buffer的使用来看,已经降低到16K

六.总结
对于记录数多的大表,表上如果存在随机的GUID字段或非顺序的字符串字段,如果这些类型上建立二级索引,对于频繁的增删改操作,会带来较高的维护成本。
当change buffer使用频繁,空间很大时,服务器性能也会出现大幅下降。这时我们可以通过删除热表的二级索引,改造分区表,清理大表数据,OPTIMIZE TABLE等操作来进行优化。

【原创】记一次MySQL大表高并发写入引发CPU飙升的排障过程的更多相关文章
- 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结
本文原作者“ manong”,原创发表于segmentfault,原文链接:segmentfault.com/a/1190000006158186 1.引言 MySQL作为开源技术的代表作之一,是 ...
- MySQL 大表优化方案(长文)
当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型 ...
- 从云数据迁移服务看MySQL大表抽取模式
摘要:MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来. 小编最近在云上的一个迁移项目中被MySQL抽取模式折磨的很惨.一开始爆内存被客户怼,再后来迁移效率低下再被怼.MySQL ...
- [记录]一则清理MySQL大表以释放磁盘空间的案例
一则清理MySQL大表以释放磁盘空间的案例 一.基本情况: 1.dbtest库554G,先清理st_online_time_away_ds(37G)表的数据,保留半年的数据: 1)删除的数据:sele ...
- MySQL InnoDB 实现高并发原理
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- php面试题二--解决网站大流量高并发方案(从url到硬盘来解决高并发方案总结)
php面试题二--解决网站大流量高并发方案(从url到硬盘来解决高并发方案总结) 一.总结 从外到内解决网站大流量高并发问题---从提交一个url开始(从用户按下搜索栏回车键开始) url最开始会到d ...
- 详解MySQL大表优化方案( 转)
当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型 ...
- MySQL 大表优化方案探讨
当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型 ...
- mysql大数据高并发处理
一.数据库结构的设计 如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能.所以,在一个系统开始实施之前,完备的数据库模型的设计是必须的. ...
随机推荐
- protobuffer
[protobuffer] 1.扩展名为.proto. 2.定义一个协议: 3.定义一个Service: 4.编译器为protoc,使用protoc: 5.style:所有的类型名均CamelCase ...
- SQL Server 2008 R2 企业版安装教程
1 安装包解压 2 解压后,打开setup.exe文件,选择安装,显示如图: 3 选择全新安装或向现有安装添加功能 4 点确定 5 输入 企业版序列号:R88PF-GMCFT-KM2KR-4R7GB- ...
- 高效使用jquery之一:请使用'On'函数
on函数是在jquery 1.7 加入的 描述: 在选定的元素上绑定一个或多个事件处理函数. 定义:.on( events [, selector ] [, data ], handler(event ...
- 凸优化(Convex Optimization)浅析
本博客已经迁往http://www.kemaswill.com/, 博客园这边也会继续更新, 欢迎关注~ 在机器学习中, 很多情况下我们都需要求得一个 问题的全局最优值(global optimum) ...
- 20155217 2016-2017-2 《Java程序设计》第8周学习总结
20155217 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 15.1日志 15.1.1日志API简介 java.util.logging包提供了日志功能 ...
- python Linux flask uwsgi nginx 在centos7.3部署
0.直接上uwsgi和nginx安装命令 linux 安装uwsgi yum groupinstall "Development tools" yum install zlib-d ...
- dockerfile创建镜像及容器
第一步: 从王总git上:http://git.oursdata.com/wangyue/dockerfiles.git 进入下图的文件夹中 然后执行以下的说明执行步骤 第二步: 开发环境dock ...
- Linux 网络编程实例
/*socket->bind->listen->accept->recv/recvfrom->send/sendto->close 客户端:socket->c ...
- Motan
https://github.com/weibocom/motan/wiki/zh_userguide http://www.cnblogs.com/mantu/p/5885996.html(源码分析 ...
- MEF实现设计上的“松耦合”(三)
1.面向接口编程:有一定编程经验的博友应该都熟悉或者了解这种编程思想,层和层之间通过接口依赖,下层不是直接给上层提供服务,而是定义一组接口供上层调用.至于具体的业务实现,那是开发中需要做的事情,在项目 ...