IO问题成顽疾,鹅厂专家来教你

| 做者 王文安,腾讯CSIG数据库专项的数据库工程师,主要负责腾讯云数据库 MySQL 的相关的工做,热爱技术,欢迎留言进行交流。mysql


在平常工做中,有时候会发现 MySQL 的状态不太对劲,这时候就会看看监控指标,可能会发现:写入 QPS 开始出现毛刺,或者 IO 的指标很高。这时候该怎么办呢?本文会从 Linux 层面入手,根据不一样的 IO 特色来分析 MySQL 数据库可能遇到的问题,并给出一些可参考的优化/缓解思路。

1、怎么看懂 IO 指标?

检查 IO 的问题会使用iostat这个命令,这里展现一下命令的效果(iostat -x 1 -m,debian 10.2):linux

image.png

iostatios

avg-cpu 天然就是 CPU 相关的指标,判断 IO 问题时能够关注 %iowait,其余指标的意义以下:sql

·r/s 和 w/s:合并事后的读请求和写请求的每秒请求数,能够当作 IOPS 来理解。数据库

·rMB/s 和 wMB/s:磁盘的读写吞吐量。数组

·rrqm/s 和 wrqm/s:每秒合并的读请求和写请求数量。缓存

·%rrqm 和 %wrqm:合并的读请求和写请求百分比。服务器

·r_await 和 w_await:读请求和写请求的平均响应时间,包含真正的处理时间和队列中的等待时间(ms)。架构

·aqu-sz:平均队列深度。性能

·rareq_sz 和 wareq_sz:一个读请求和写请求的平均物理大小(KB)。

·scvtm:计算出来的平均 IO 响应时间,目前已经不许确,不用再关注。

·%util:若是使用了 RAID 或者 SSD,则忽略这个指标,仅在单块机械盘上准确。

通常来讲,评价一块 IO 设备(忽略机械盘的状况,没有评价的意义)是否达到了高负载状况,能够看这几个指标:r/s,w/s,rMB/s,wMB/s,r_await,w_await,aqu-sz。

2、MySQL 与 IO

因为 MySQL 涉及到 IO 相关的参数会比较多,所以这里仅一部分常常用到的参数以及在测试&模拟中使用默认设置:

参数

设置

备注

innodb_io_capacity

16000

定义了后台任务可用的 IOPS 量

innodb_io_capacity_max

32000

定义了后台任务可用的最大 IOPS 量

innodb_flush_log_at_trx_commit

1

控制事务的提交策略,具体信息请参考官方文档

sync_binlog

1

控制 binlog 落盘的频率,具体信息请参考官方文档

innodb_io_capacity 和 innodb_io_capacity_max 是最直接限制 IOPS 的指标,大多数时候,SSD 能够设置成 16000 或者更高的数值,若是是云主机或者其余的共享存储设备,则须要了解一下详细的 IOPS 上限再具体调整。trx_commit 和 sync_binlog 这两个参数也放进来的缘由是不一样的参数组合对 IO 的压力也会有区别。一般的用法是双 1 或者 20(二零),参考官方文档的描述,双 1 在每次提交事务的时候都会刷盘,对 IO 的压力要高很多;20 则是滞后刷盘,对 IO 的压力会较小,所以写入 QPS 会高一些。

另外,能够关注到一个细节,innodb_io_capacity 的描述对象是:后台任务。这表明着 MySQL 后台的 flush,purge 操做会受到这个参数设置的限制。

3、测试环境

本次测试使用腾讯云服务器的高 IO 型 IT3 实例,自带了 3TB 的本地 NVME。因为腾讯云平台限制了系统版本(debian 9),所以 iostat 在输出内容上稍有差别,可是不影响分析,简单用 fio 跑了一下 16k(innodb_page_size 的默认配置) 的 IO 性能:

类型

IOPS

吞吐量(MB)

随机读

121959

1905

随机写

98326

1536

随机读写(读部分)

47129

750

随机读写(写部分)

47152

754

那么,为何测试环境要用一个彻底不会有 IO 瓶颈的呢?这是为了方便展现调整 MySQL 以后的效果。若是整套系统的 IO 设备负载长期处于高水位的话,最佳优化策略是升级 IO 设备,而不是调整 MySQL。所以全部的分析和应对的场景都属于中、短期内的高 IO 负载。

4、IO 分析

1. 纯写入

先看一种比较纯粹,可是较少出现的 IO 负载场景:

image.png

iostat_wo

这种类型的指标有一个明显的特色:IO 负载中没有,或者几乎没有读取相关的压力。这种负载的特征通常是缓存足够放下全部的数据,所以不须要从磁盘上读数据,压力所有在写入上。

首先能想到的,显然是trx_commit 和 sync_binlog 这两个参数,把双 1 改为 20 的配置,产生 QPS 变化的缘由也比较好理解:本来一个事务须要刷一次磁盘,变成多个事务刷盘操做合并到了一块儿,就像是提升了每一个 IOPS 的“事务处理效率”,好比从 1 事务/IOPS 变成了 N 事务/IOPS。

除了提升“每一个 IOPS 的事务处理效率”之外,其实还会有另一种思路:适当限制后台任务的 IOPS。实际上 MySQL 的写入会涉及到很是多的 buffer,log,并产生后台任务相关的数据,出现中等时间的高写入场景时,后台任务通常会慢慢堆积须要 flush 和 purge 的数据,若是 innodb_io_capacity 和 innodb_io_capacity_max 的参数设置得比较高,可能会让后台任务消耗过多的 IO 资源,这时候适当调低一些能够在一段时间内稳住写入 QPS,等高写入的压力过去以后再回滚设置。

另外,若是有更加精细化的调整方式,应该会有更好的效果,目前只能靠这个参数一刀切,不过不要改得过低,由于当后台任务堆积的数据过多,触发强制刷脏/checkpoint 等机制时,会大幅度的侵占 IO 资源,致使很是剧烈的写入 QPS 波动,这一点须要注意。

这里给出“反向调整”的效果,日志数据取自于某一个 sysbench 客户端,在 2050s 左右的时候大幅度调高了 io_capacity:

2. 纯读取

另一种比较纯粹的场景,天然就是纯读取了,例如:

image.png

iostat_ro

纯读取的 IO 特征说明缓存不够大,须要从磁盘读取热数据。那么增长内存和调高 innodb_buffer_pool_size,把更多的数据放到内存中就是最好的解决方案。至于须要加多少内存,能够结合实际业务 SQL 的响应时间(作好索引优化以后)和 buffer_pool 的命中率,从经验值来看,命中率(show engine innodb status里面)高于 99.5% 是比较理想的,若是实际 SQL 的响应时间不知足业务的需求,那么就能够根据实际命中率来估算须要的内存大小。

因为从 5.7 开始,MySQL 支持动态调整 innodb_buffer_pool_size 这个参数了,所以变动带来的影响相对小了不少,不过调整仍是有代价的,尽可能在业务低峰期操做。

3. 读写混合

最多见的确定是读写混合的场景,好比像这样子的:

image.png

iostat_rw

分析起来会相对复杂一点,可是结合纯读取和纯写入的分析以后,能够比较容易想到以下的可能性:

场景一:读写混合的场景。

场景二:纯写入的场景,可是内存放不下全部的数据,须要从磁盘读取以后再修改。

先看比较简单的场景2,本质上仍是相似于纯写入场景,可是因为内存不够大,所以在排查 MySQL 的读写 SQL 比例(global status 中的 com_xxx 系列数据)以后,能够参考纯写入这个章节的内容进行分析处理。

虽然场景 1 会复杂一些,可是结合纯写和纯读的内容,分析的思路就有了,好比依次思考以下问题:

业务读写比例大概是多少?

IO 系统的读性能问题比较大仍是写性能问题比较大?

若是说:

业务读的比例高(例如 >4:1),IO 系统读的性能问题比较大:那么参考纯读取的内容,调高 buffer_pool_size 。

业务读的比例高(例如 >4:1),IO 系统写的性能问题比较大:那么参考纯写入的内容,调整事务提交策略或者 io_capacity。另外,此类场景多是由于在大批量变动数据,也能够考虑一下优化这种业务行为。

业务写的比例高(例如<4:1),IO 系统读的性能问题比较大:那么参考纯读取的内容。

业务写的比例高(例如<4:1),IO 系统写的性能问题比较大:那么参考纯写入的内容。

业务的读写比例没有什么明显的特色,IO 系统读写的性能问题都比较严重:考虑以上全部的方法,包括升级硬件。

4.一些tips:

吞吐量,IOPS 和一些分散读写压力的手段

吞吐量和 IOPS ,通常状况下衡量 IO 系统性能最直观的指标,并无特别的说起,主要缘由仍是判断起来很简单:若是iostat的指标已经达到或者接近了实际硬件的指标(好比达到了 75%),那么根据业务量增加的状况及早规划硬件升级或者其余的手段来分散读写压力。

常规的手段,能够简单的遵循如下场景来酌情使用:读多写少读写分离,写多读少拆库拆表加缓存。

判断 MySQL IO 状况的指标

若是 MySQL 在 IO 方面出现了阻塞的现象,那么能够观察如下几个指标:

参数名

意义

备注

Innodb_data_pending_fsyncs

当前阻塞的 fsync 操做

通常为 0,比较高的话,看一下 innodb_flush_method 的设置

Innodb_data_pending_reads

当前阻塞的 read 操做

通常为 0,若是指标较高且影响业务的话,参考读压力的应对方式

Innodb_data_pending_writes

当前阻塞的 write 操做

通常为 0,若是指标较高且影响业务的话,参考写压力的应对方式

Innodb_os_log_pending_fsyncs

写 redo log 时,当前阻塞的 fsync 操做

通常为 0,若是大于 0 的话,一般就是 IO 设备的瓶颈,考虑把 redo log 迁移到 SSD 或者作 IO 隔离,独占 IO 设备的性能

Innodb_os_log_pending_writes

写 redo log 时,当前阻塞的 write 操做

通常为 0,若是指标较高且影响业务的话,参考写压力的应对方式

InnoDB 还有不少其余的 read 和 write 的指标,经过show global status like '%innodb%read%'之类的操做均可以看到,可是这类指标通常是累计值,须要对比上一个取值时间的差值才能有比较实际的做用,一般也是用来判断 MySQL 的读写比例用,结合上表的 pending 数据和其余的系统指标来综合判断 IO 系统的负载。这些指标也是建议监控起来的。

5、总结

解决 IO 问题的手段是多样化的:最省事的升级硬件;最快捷的调整 MySQL(本文主要内容);比较经常使用的架构调整手段(读写分离,拆库拆表);结合实际状况来优化业务的行为(合并单行操做的 DML,拆分单个大量更新数据的 DML 语句等)。

虽然不能对上述手段进行全面的介绍,可是iostat提供的信息在分析 MySQL 瓶颈时仍是很是有用的,本文仅从硬件的负载特色出发,简述了调整 MySQL 的一些思路。实际上须要多种手段结合起来才能比较好的应对 IO 方面的问题。

本文由博客一文多发平台 OpenWrite 发布!

相关文章
相关标签/搜索