原文 https://www.percona.com/blog/2020/05/14/tuning-mysql-innodb-flushing-for-a-write-intensive-workload/

前言

这篇文章是讲述 InnoDB 刷盘策略系列文章的第三篇。本文主要讲述 性能调优。另外2篇文章参考

https://www.percona.com/blog/2020/01/22/innodb-flushing-in-action-for-percona-server-for-mysql/

https://www.percona.com/blog/2019/12/18/give-love-to-your-ssds-reduce-innodb_io_capacity_max/

理解调优原理是非常重要的,因为我们不想将业务性能变的更糟糕,也不想SSD 磁盘被烧坏。我们将按照小节来介绍每个优化参数。

了解调优原理非常重要,因为我们不想让事情变得更糟或烧毁我们的 SSD。我们将每个变量或密切相关的变量按照章节的方式进行介绍。这些变量根据 MySQL 或Percona Server for MySQL版本和是否有效进行分组。如果给定变量的含义在版本之间发生变化,则给定变量可能会多次出现。可能还有其他变量会影响 InnoDB 处理写入密集型工作负载的方式。希望本文能涵盖最重要的内容。

MySQL 8.0.19 之前的版本

innodb_io_capacity

该参数的默认值是200,如果你阅读过我们之前写的文章, innodb_io_capacity 定义了 InnoDB 后台线程刷脏页时的 iops 个数。

The innodb_io_capacity variable defines the number of I/O operations per second (IOPS) available to InnoDB background tasks, such as flushing pages from the buffer pool and merging data from the change buffer.

自适应刷新独立于 innodb_io_capacity 。一般来说 调大  innodb_io_capacity 的原因很少:

减少变更缓冲滞后

增加空闲刷新率(当 LSN 恒定时)

提高脏页百分比刷新率

我们很难找到任何理由来增加空闲刷新率 。此外,不应使用脏页刷新百分比(见下文)。这会导致更换器缓冲滞后。如果在执行“show engine innodb status\G”时,更改缓冲区中经常有大量条目,如下所示:

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1229, free list len 263690, seg size 263692, 40050265 merges
merged operations:insert 98911787, delete mark 40026593, delete 4624943
discarded operations:insert 11, delete mark 0, delete 0

如果有 1229 个未应用的更改,您可以考虑提高 innodb_io_capacity

innodb_io_capacity_max

innodb_io_capacity 的值为默认值时, innodb_io_capacity_max 的值为2000。该参数控制每秒 InnoDB 刷新多少 IOPS。(官方文档提示 以iops 为单位,原博里面的单位是 page )

If flushing activity falls behind, InnoDB can flush more aggressively, at a higher rate of I/O operations per second (IOPS) than defined by the innodb_io_capacity variable. The innodb_io_capacity_max variable defines a maximum number of IOPS performed by InnoDB background tasks in such situations.

这与 InnoDB 生成的写入 IOPS 大致匹配。您的硬件应该能够每秒执行那么多页面刷新。如果您看到以下消息:

[Note] InnoDB: page_cleaner: 1000ms intended loop took 4460ms. The settings might not be optimal. (flushed=140, during the time.)

从上面的 MySQL 日志中可以看出来, 硬件的 IO 能力跟不上InnoDB 刷脏的速度,(理论上应该1000毫秒内完成的动作实际上花费4460毫秒将脏页刷新到磁盘,它接受脏页的数量远远大于它每秒能够处理脏页的能力。) 所以你应该降低 innodb_io_capacity_max 的值。

理想值应允许checkpoint age尽可能高,同时保持在最大检checkpoint age的 75% 以下。checkpoint age 越高,数据库需要执行的写入操作就越少。同时,如果 checkpoint age 超过 75%,您将面临停顿的风险。需要进行权衡,写入性能与短期停顿的风险。根据您面临的性能痛点和短停顿的风险选择合理的值。如果您部署了Percona 监控和管理(PMM),“MySQL InnoDB 详细信息”仪表板中的 "InnoDB Checkpoint Age" 非常有用。下面是一个借助 sysbench 生成的简单示例:

负载从 15:02 开始,checkpoint age 迅速达到 20% 左右。然后,在 15:13,innodb_io_capacity_max 降低,checkpoint age 提高到 50% 左右。这种提高导致刷新率下降了大约一半,这可以在另一个 PMM 图“InnoDB Data I/O”中看到

Percona Server for MySQL 还公开了所有相关变量:

mysql> show global status like 'innodb_ch%';
+---------------------------+------------+
| Variable_name             | Value      |
+---------------------------+------------+
| Innodb_checkpoint_age     |  400343763 |
| Innodb_checkpoint_max_age | 1738750649 |
+---------------------------+------------+
2 rows in set (0.00 sec)mysql> show global variables like 'innodb_adaptive_fl%';
+------------------------------+-------+
| Variable_name                | Value |
+------------------------------+-------+
| innodb_adaptive_flushing     | ON    |
| innodb_adaptive_flushing_lwm | 10    |
+------------------------------+-------+
2 rows in set (0.00 sec)

使用上面的示例,checkpoint age 大约是最大值的 23%,远高于 innodb_adaptive_flushing_lwm 中定义的 10%。如果checkpoint age是数据库负载下的典型值并且它永远不会提高到更高的值,则 innodb_io_capacity_max 可以降低一点。相反,如果 checkpoint age 经常接近甚至超过 75%,则 innodb_io_capacity_max 的值太小。

page_cleaner_thread :脏页清理线程负责将脏页从内存写到磁盘。因此为了避免该问题,可降低每秒循环期间搜索脏页的深度(innodb_lru_scan_depth)和 降低 innodb_io_capacity 的值,减少每秒 io 负载。

innodb_max_dirty_pages_pct  innodb_max_dirty_pages_pct_lwm

这2个参数控制 MySQL 5.0 版本的刷新方式,作为缓冲池中脏页百分比的函数。应该通过将 innodb_max_dirty_pages_pct_lwm 设置为 0 来禁用它。5.7 中的默认值为0,但奇怪的是,在 8.0 中的默认值是10 。

注释:

1 当innodb中的脏页比例超过 innodb_max_dirty_pages_pct_lwm 的值时,这个时候innodb就会开始刷新脏页到磁盘。

2 当innodb中的脏页比例超过 innodb_max_dirty_pages_pct_lwm 的值,而且还超过innodb_max_dirty_pages_pct 时  innodb就会把脏页更快的刷新到磁盘。

3 还有一种情况叫做sharp checkpoint ,当innodb要重用之前的redo文件时,就会把innodb_buffer_pool中所有与这个文件有关的页面都要刷新到磁盘,这样有可能引起磁盘的IO风暴,影响性能和系统可用性。

innodb_max_dirty_pages_pct_lwm =0 时,表示禁用,此时 innodb_buffer_pool中的脏页比例会操持在75%左右。

innodb_page_cleaners

innodb_page_cleaners 控制刷新脏页的线程数,专门用于扫描缓冲池实例中的脏页并刷新它们。此外,您不能拥有比缓冲池实例更多的 刷新线程数。此变量的默认值为 4。

当该参数为4时,InnoDB使用 4 线程 能够以非常高的速率刷新。实际上,除非您使用 Percona Server for MySQL parallel doublewrite buffers feature 功能,否则双写缓冲区很可能会在更干净的线程之前成为瓶颈。

innodb_purge_threads

innodb_purge_threads 控制 用于清除操作的线程数。清除操作 清理已经被删除的行和 undo log。这些线程还会截断磁盘上撤消空间。清除线程的默认数量为 4。

通常情况下,业务压力很难能够使 4 个清除线程达到饱和状态,默认值是足够的。清除线程的大部分工作都在内存中完成。除非您的业务数据库有非常大的缓冲池和高写入负载,否则默认值 4 就足够了。如果您在“show engine innodb status”中看到比较高的 history length 的值而没有任何长时间运行的事务,则可以考虑增加清除线程的数量

大多数业务场景可以不用调整,写入负载比较大(比如 tps 大于 2000 甚至5000 以上 )的还是需要调整到合适的值。

innodb_read_io_threads  和 innodb_read_io_threads

令人惊讶的是,在具有异步 IO 的 Linux 上,这些线程几乎没有相关性。例如,我们的一个客户的实例配置 16 个读取 io 线程和 16 个写入 io 线程。数据库实例正常运行时间约为 35 天,mysqld 进程消耗 104 小时 CPU,读取 281 TB,并将 48 TB 写入磁盘。数据集主要由压缩的 InnoDB 表组成。您可能认为对于这样的服务器,IO 线程会很忙,对吧?让我们来看看:

root@prod:~# ps -To pid,tid,stime,time -p $(pidof mysqld)PID TID STIME  TIME72734  72734 Mar07 00:23:0772734  72752 Mar07 00:00:00 -> ibuf (unused)72734  77733 Mar07 00:01:1672734  77734 Mar07 00:01:5172734  77735 Mar07 00:05:46 -> read_io72734  77736 Mar07 00:06:04 -> read_io72734  77737 Mar07 00:06:06 -> read_io… 11 lines removed72734  77749 Mar07 00:06:04 -> read_io72734  77750 Mar07 00:06:04 -> read_io72734  77751 Mar07 00:35:36 -> write_io72734  77752 Mar07 00:34:02 -> write_io72734  77753 Mar07 00:35:14 -> write_io… 11 lines removed72734  77766 Mar07 00:35:18 -> write_io72734  77767 Mar07 00:34:15 -> write_io

我们添加了注释以帮助识别 IO 线程,并删除了许多无关的行。读取 IO 线程的平均 CPU 时间为 6 分钟,而写入 IO 线程的 CPU 时间稍高一些,为 35 分钟。这些都是非常小的数字,显然,设置这两个参数的值为 16 在这两种情况下都太多了。默认值为 4 时,读取 IO 线程的 CPU 时间约为 25 分钟,写入 IO 线程的 CPU 时间约为 2 小时。在 34 天的正常运行时间中,这些时间不到正常运行时间的 1%。

innodb_lru_scan_depth

innodb_lru_scan_depth 是一个命名非常糟糕的变量。更好的名称是 innodb_free_page_target_per_buffer_pool,该参数控制InnoDB 试图在每个缓冲池实例中保持空闲的页面数量,以加快读取和页面创建操作。该变量的默认值为 1024。

这个变量的危险在于,如果该参数设置比较大的值 且数据库实例 有多个 buffer pool instances ,可能会导致浪费大量内存。对于 64 个缓冲池实例,默认值1024 表示 1GB 空闲内存。设置此变量的最佳方法是通过查看“show engine innodb status\G” ,并使用  grepping 查找“Free buffers”。这是一个例子。

mysql> pager grep 'Free buffers'
PAGER set to 'grep 'Free buffers''
mysql> show engine innodb status\G
Free buffers    8187
Free buffers    1024
Free buffers    1023
Free buffers    1022
Free buffers    1020
Free buffers    1024
Free buffers    1025
Free buffers    1025
Free buffers    1024
1 row in set (0.00 sec)

第一行是所有buffer pools free pages 的总数,InnoDB 为每个缓冲池实例保留大约 1024 个空闲页面。所有buffer pool instance 最低保留1020个page 。根据经验,您可以使用当前变量值(此处为 1024)减去相当数量样本中的最小观察值,然后将结果乘以 4。如果1020 是最小值,根据算法得到 (1024-1020)*4 ~ 16。变量的最小允许值是 128。我们计算了 16,小于 128 的值,所以应该使用 128。

innodb_flush_sync

设置 innodb_flush_sync=ON , 当checkpoint age 大于 94% 时 ,允许 InnoDB 刷新磁盘忽略 innodb_io_capacity_max 值。通常这是正确的,因此默认值为“ON”。唯一的例外是读取的 SLA 非常严格的情况。允许 InnoDB 使用超出 innodb_io_capacity_max 的 IOPS 进行刷新会与读取负载竞争,并且会增加读的响应时间。

innodb_log_file_size and innodb_log_files_in_group

参数 innodb_log_file_size and innodb_log_files_in_group 控制 redo log 文件大小以及 redo日志组内的文件数量。本质上,redo log 记录最新的数据库改变的日志。日志文件最大大小为 512GB 减去一个字节。较大的重做日志环形缓冲区允许页面在缓冲池中保持更长时间的脏状态。如果在此期间,数据库接收更多的更新写入操作,则对磁盘的写压力基本上是减弱的。减轻写负载有利于提高性能,尤其是数据库是IO-bound 类型的。当然一个非常大的重做日志会导致崩溃后的恢复时间需要更多时间,但现在这已经不是什么问题了。

这里翻译不是很通顺, 我在理解是 如果写压力比较大,可以提高 innodb_log_buffer_size 的值 64M 甚至更高,redo log file 设置1-2G ,减少日志频繁覆盖切换。

官方文档的解释:

The size in bytes of the buffer that InnoDB uses to write to the log files on disk. The default is 16MB. A large log buffer enables large transactions to run without the need to write the log to disk before the transactions commit.

innodb_adaptive_flushing_lwm

innodb_adaptive_flushing_lwm 参数控制 adaptive flushing 的最低水位,到达该值,则触发 adaptive flushing。默认值是10 ,最大值为70 。

设置 innodb_adaptive_flushing_lwm 比较高的好处和设置一个比较大的 innodb_log_file_size 类似,但它使数据库更接近最大checkpoint age 的边缘。使用较高的低水位值,一般情况下,写入性能会更好,但可能会出现短暂的hang。对于生产环境,增加 Innodb_log_file_size 优于增加 innodb_adaptive_flushing_lwm。但是,暂时地,动态提高该值可以加速逻辑导出或提高slave 追赶master 的速度。(打开非双1模式和并行复制更有效)

innodb_flushing_avg_loops

该参数控制 adaptive flushing 的算法,innodb_flushing_avg_loops 定义了InnoDB保持先前计算的刷新状态快照的迭代次数,控制自适应刷新对前台工作负载变化的响应速度。就是说控制统计前N个page flush速率,避免太快flush。

高的值意味着InnoDB保持先前计算的快照的时间更长,因此自适应刷新响应更慢。如日志空间利用率未达到75%,则应该使用较高的 innodb_flushing_avg_loops 值来保持尽可能平滑的刷新。对于具有极端负载峰值或日志文件比较小的数据库系统,应设置该参数为比较小的值允许 flush 以密切跟踪工作负载更改,并有助于避免达到 75% 的日志空间利用率。

调优的时候很少修改该值。

MySQL Community After 8.0.19

innodb_io_capacity

在 MySQL 8.0.19 之前,当 InnoDB 需要在刷新磁盘时,它会刷新大批量的页面。这种方法的问题是刷新顺序可能不是最佳的,太多的页面可能来自同一个缓冲池实例。

从 MySQL 8.0.19 开始,刷新是以 innodb_io_capacity 大小的块完成的。块之间没有等待时间,因此与 IO 容量没有关系。这种方式有助于更好地平衡 flush 顺序并降低潜在的时间。

这点还没研究 两者之间的差异。

innodb_idle_flush_pct

在 MySQL 8.0.19 中,空闲刷新率不再由 innodb_io_capacity 直接控制,而是乘以 innodb_idle_flush_pct 表示的百分比。InnoDB 将剩余的 IO 容量用于 insert buffer thread. 。当数据库变得空闲时,意味着 LSN 值不会移动,InnoDB 通常会先刷新脏页,然后应用存储在更改缓冲区中的二级索引更改。如果这不是您想要的行为,请降低该参数以便给  change buffer. 提供一些 IO。

Percona Server for MySQL 5.7.x and 8.0.x

innodb_cleaner_lsn_age_factor

Percona Server for MySQL 有一个新的默认自适应刷新算法 high_checkpoint,它本质上允许更多的脏页。此行为由变量 innodb_cleaner_lsn_age_factor控制。您可以通过将变量设置为 legacy 来恢复默认的 MySQL 算法。由于您的目标应该是拥有尽可能多的脏页,而不会遇到刷新风暴和停顿,因 high_checkpoint算法将为您提供帮助。如果你的实例有比较高的 checkpoint age,也许旧算法会更好。有关此主题的更多信息,请参阅我们之前的帖子。

innodb_empty_free_list_algorithm

该变量控制  InnoDB 在缓冲池实例中寻找空闲页面的行为。它有两个值 : legacybackoff

设置为legacy :只有在“show engine innodb status\G”中经常有“接近0”时才有意义。在这种情况下,LRU 管理器线程可能会获取 free list mutex 并导致与其他线程的争用。

设置为backoff时,线程将在找不到空闲页面后休眠一段时间以降低争用。默认为backoff ,通常在大多数情况下没问题。

该参数是Percona Server 独有的。MySQL 社区版无该参数。

结论

还有其他的参数影响 InnoDB 的写操作,但是本文提到的 这些参数 应该是比较重要的。通常来说,不要过度调整数据库实例并尝试一次更改一个设置。

以上我们对影响刷新的 InnoDB 变量的理解,并且这些参数在各种 Percona 客户场景中得到实际验证。我们还花费大量时间阅读代码以了解 InnoDB 的运行机制。像往常一样,我们对评论持开放态度,但如果可能,请尝试通过引用代码或可重现的用例来支持任何反对我们观点的论点。

参考

https://dev.mysql.com/doc/refman/5.7/en/optimizing-innodb-diskio.html https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool-flushing.html https://www.percona.com/blog/2020/01/22/innodb-flushing-in-action-for-percona-server-for-mysql/

针对 MySQL/InnoDB 刷盘调优相关推荐

  1. mysql linux 性能提高_针对MySQL的Linux性能调优技巧

    原文来自Percona工程师:Linux performance tuning tips for MySQL 为了方面阅读,我没依照原文按行逐句的进行翻译.另外,我自己的扩充了一下基础知识点,很多知识 ...

  2. mysql memory=off_MySQL内存调优

    原文链接: MySQL Memory Allocation -- by Rick James 原文日期: Created 2010; Refreshed Oct, 2012, Jan, 2014 翻译 ...

  3. lamp mysql大小限制_LAMP 调优之:MySQL 服务器调优

    关于 MySQL 调优 有 3 种方法可以加快 MySQL 服务器的运行速度,效率从低到高依次为: 替换有问题的硬件. 对 MySQL 进程的设置进行调优. 对查询进行优化. 替换有问题的硬件通常是我 ...

  4. mysql数据刷盘过程详解_MySQL延迟问题和数据刷盘策略流程分析

    一.MySQL复制流程 官方文档流程如下: MySQL延迟问题和数据刷盘策略 1.绝对的延时,相对的同步 2.纯写操作,线上标准配置下,从库压力大于主库,最起码从库有relaylog的写入. 二.My ...

  5. mysql数据刷盘_MySQL延迟问题和数据刷盘策略

    一. MySQL 复制流程 官方文档流程图如下: 1.绝对的延时,相对的同步 2.纯写操作,线上标准配置下,从库压力大于主库,最起码从库有relaylog的写入. 二.MySQL延迟问题分析 1.主库 ...

  6. mysql监控、性能调优及三范式理解

    @酷勤网-程序员的那点事 <mysql监控.性能调优及三范式理解>下文介绍了关于mysql监控.性能调优及三范式理解的内容.mysql监控.性能调优及三范式理解(来自: 博客园 ) @酷勤 ...

  7. mysql数据刷盘_MySQL InnoDB 日志管理机制中的MTR和日志刷盘

    1.MTR(mini-transaction) 在MySQL的 InnoDB日志管理机制中,有一个很重要的概念就是MTR.MTR是InnoDB存储擎中一个很重要的用来保证物理写的完整性和持久性的机制. ...

  8. 生产环境mysql安装规划及调优实践--mysql8.0.29为例

    以前运维人员部署在生产环境的mysql又被扫描出安全漏洞,需要进行修补.这种事情本来应该是很简单的事儿,但如今执着于软件领域技术的人是越来越少,竟然没有人愿意去做去学,都想等着别人去处理,最终还是得老 ...

  9. MySQL 索引和 SQL 调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

最新文章

  1. java error could_Java.lang.Error: Properties init: Could not determine current working directory.
  2. 用亲和性分析方法推荐电影
  3. python读取文件with open_python 文件读写操作open和with的用法
  4. 工作单元php,php – 无法从工作单元测试用例构建最简单的套件
  5. php记录代码执行时间
  6. extjs 基础部分
  7. nvidia-smi‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件
  8. Application package 'AndroidManifest.xml' must have a minimum of 2 segments.
  9. 'React' must be in scope when using JSX react/react-in-jsx-scope报错:
  10. R语言向matlab转化,我有一段MATLAB的程序,现在想转换成R语言代码
  11. MySql重启命令与数据库安装目录
  12. sharp.js中文文档
  13. 机房环境监控管理解决方案—温湿度、烟感、PM2.5、TVOC等监测
  14. 【解决】gnglia报错:Can‘t open PID file /usr/local/ganglia/var/run/gmetad.pid (yet?)
  15. C++ 逻辑与或非 逻辑与逻辑或 逻辑非
  16. 华硕Afudos更新bios方法介绍
  17. 微信h5页面禁止下拉方法
  18. MySQL错误:Column ‘pno‘ in field list is ambiguous是什么问题呢?
  19. 上升了百分之几怎么算_求增加百分之几的应用题
  20. 项目研发管理实施经验谈(1)

热门文章

  1. 解决GitHub Pages屏蔽百度爬虫的方法
  2. c++的HTTP请求返回网页数据
  3. 企业微信自建应用开发防止踩坑
  4. python 采集新闻_Python多篇新闻自动采集
  5. 生化危机8:村庄 v1.0 二十三项修改器
  6. 数据库基本知识总结-----MySQL
  7. extjs 动态设置columnModel的某一列为可编辑
  8. windows10管理右键菜单
  9. 若依整合mybaitsplus
  10. 学计算机会不会有辐射,电脑真的会发出辐射吗?废话,当然会!