如何解决 mysql 警告:"InnoDB: page_cleaner: 1000ms intended loop took XXX ms. The settings might not be optimal "?

How to solve mysql warning: "InnoDB: page_cleaner: 1000ms intended loop took XXX ms. The settings might not be optimal "?

I 运行 a mysql import mysql dummyctrad < dumpfile.sql 在服务器上,它需要很长时间才能完成。转储文件大约5G。服务器是Centos 6,内存=16G,8核处理器,mysql v 5.7 x64-

这些正常吗messages/status"waiting for table flush"和留言InnoDB: page_cleaner: 1000ms intended loop took 4013ms. The settings might not be optimal

mysql 日志内容

2016-12-13T10:51:39.909382Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 4013ms. The settings might not be optimal. (flushed=1438 and evicted=0, during the time.)
2016-12-13T10:53:01.170388Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 4055ms. The settings might not be optimal. (flushed=1412 and evicted=0, during the time.)
2016-12-13T11:07:11.728812Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 4008ms. The settings might not be optimal. (flushed=1414 and evicted=0, during the time.)
2016-12-13T11:39:54.257618Z 3274915 [Note] Aborted connection 3274915 to db: 'dummyctrad' user: 'root' host: 'localhost' (Got an error writing communication packets)

进程列表:

mysql> show processlist \G;
*************************** 1. row ***************************
     Id: 3273081
   User: root
   Host: localhost
     db: dummyctrad
Command: Field List
   Time: 7580
  State: Waiting for table flush
   Info: 
*************************** 2. row ***************************
     Id: 3274915
   User: root
   Host: localhost
     db: dummyctrad
Command: Query
   Time: 2
  State: update
   Info: INSERT INTO `radacct` VALUES (351318325,'kxid ge:7186','abcxyz5976c','user100
*************************** 3. row ***************************
     Id: 3291591
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: starting
   Info: show processlist
*************************** 4. row ***************************
     Id: 3291657
   User: remoteuser
   Host: portal.example.com:32800
     db: ctradius
Command: Sleep
   Time: 2
  State: 
   Info: NULL
4 rows in set (0.00 sec)

Update-1

mysqlforum ,innodb_lru_scan_depth

将 innodb_lru_scan_depth 值更改为 256 改进了插入查询的执行时间 + 日志中没有警告消息,默认值为 innodb_lru_scan_depth=1024;

SET GLOBAL innodb_lru_scan_depth=256;

InnoDB: page_cleaner: 1000ms intended loop took 4013ms. The settings might not be optimal. (flushed=1438 and evicted=0, during the time.)

该问题是 MySQL 实例的典型问题,您对数据库的更改率很高。通过 运行 您的 5GB 导入,您正在快速创建脏页。创建脏页时,页面清理器线程负责将脏页从内存复制到磁盘。

就您而言,我假设您不会一直导入 5GB。所以这是一个异常高的数据加载率,而且是暂时的。您可以忽略这些警告,因为 InnoDB 会逐渐赶上来。


下面是对导致此警告的内部机制的详细解释。

每秒一次,页面清理器扫描缓冲池以查找脏页以从缓冲池刷新到磁盘。您看到的警告显示它有很多脏页要刷新,将一批脏页刷新到磁盘需要 4 多秒,而它应该在 1 秒内完成这项工作。换句话说,它贪多嚼不烂。

您通过将 innodb_lru_scan_depth 从 1024 减少到 256 来调整它。这减少了页面清理器线程在其每秒一次的循环中搜索脏页面到缓冲池的深度。你要求它咬得更小。

请注意,如果您有很多缓冲池实例,它会导致刷新做更多的工作。它会减少每个缓冲池实例的 innodb_lru_scan_depth 工作量。所以你可能在不降低扫描深度的情况下增加缓冲池的数量,无意中造成了这个瓶颈。

innodb_lru_scan_depth 的文档说 "A setting smaller than the default is generally suitable for most workloads." 听起来他们给这个选项的默认值太高了。

您可以使用 innodb_io_capacityinnodb_io_capacity_max 选项限制后台刷新使用的 IOPS。第一个选项是对 InnoDB 请求的 I/O 吞吐量的软限制。但是这个限制是灵活的;如果刷新速度落后于新脏页创建的速度,InnoDB 将动态增加刷新率超过此限制。第二个选项定义了 InnoDB 可以增加刷新率的更严格限制。

如果刷新速度能跟上创建新脏页的平均速度,那你就没事了。但是,如果您持续创建脏页的速度快于刷新脏页的速度,最终您的缓冲池将被脏页填满,直到脏页超过缓冲池的 innodb_max_dirty_page_pct。此时刷新率会自动增加,可能会再次导致page_cleaner发送警告。

另一种解决方案是将 MySQL 放在具有更快磁盘的服务器上。您需要一个 I/O 系统来处理页面刷新所需的吞吐量。

如果您在平均流量下一直看到此警告,您可能试图在此 MySQL 服务器上执行过多的写入查询。可能是时候横向扩展,并将写入拆分到多个 MySQL 实例,每个实例都有自己的磁盘系统。

阅读有关页面清理器的更多信息:

瓶颈是将数据保存到 HDD。无论你有什么硬盘:SSD、普通硬盘、NVMe 等

请注意,此解决方案主要适用于 InnoDB

我遇到了同样的问题,我应用了几个解决方案。

第 1 步:检查错误

atop -d 将显示磁盘使用情况。如果磁盘是 'busy',则尝试停止对数据库的所有查询(但不要停止 mysql 服务器服务!)

要监控您有多少查询,请使用 mytop、innotop 或等效工具。

如果您有 0 个查询,但磁盘使用率在几秒/几分钟后仍然接近 100%,那么这意味着 mysql 服务器正在尝试刷新脏页/做一些清理工作之前提到过(Bill Karwin 的伟大 post)。

那么你可以尝试应用这样的解决方案:

第二:硬件优化

如果您的阵列不在 RAID 1+0 中,请考虑使用此类解决方案将数据保存速度提高一倍。尝试通过写入数据来扩展 HDD 控制器的可能性。尝试使用 SSD 或更快的 HDD。应用此解决方案取决于您的硬件和预算可能性,并且可能会有所不同。

第三:软件调优

如果 harware cotroller 工作正常,但你想提高保存数据的速度,你可以在 mysql 配置文件中设置:

3.1.

innodb_flush_log_at_trx_commit = 2 -> 如果 you/re 使用 innodb tables。根据我的经验,每个文件一个 table 效果最好:

innodb_file_per_table = 1

3.2.

继续使用 InnoDB:

innodb_flush_method = O_DIRECT
innodb_doublewrite = 0
innodb_support_xa = 0
innodb_checksums = 0

以上几行通常减少了需要保存在 HDD 中的数据量,因此性能更高。

3.3

general_log = 0
slow_query_log = 0

以上几行禁用保存日志,当然这又是要保存在硬盘上的另一部分数据

3.4 再次检查发生了什么,例如

tail -f /var/log/mysql/error.log

第四:一般说明

一般说明:

这是在 MySQL 5.6 和 5.7.22

下测试的
  • OS:Debian 9

  • RAID: 1 + 0 SSD 驱动器

  • 数据库: InnoDB tables

    innodb_buffer_pool_size = 120G innodb_buffer_pool_instances = 8 innodb_read_io_threads = 64 innodb_write_io_threads = 64

服务器内存总量:200GB

这样做之后,您可能会观察到更高的 CPU 使用率;这很正常,因为写入数据更快,所以 CPU 会更努力。

如果您使用 my.cnf 这样做,当然不要忘记重新启动 MySQL 服务器。

第五:补充

我很感兴趣,我做了这个怪癖:

SET GLOBAL innodb_lru_scan_depth=256;

上面提到过。

使用大型 tables 我发现性能没有变化。

经过上述更正后,我并没有消除警告,但整个系统的运行速度明显加快。 以上只是一个实验,但我已经测量了结果,对我有一点帮助,希望对其他人有用。

这可能只是一般文件系统性能不佳的指示 - 不相关问题的症状。在我的例子中,我花了一个小时研究这个,分析我的系统日志,并且几乎到了调整 MySQL 配置的地步,当我决定检查我的基于云的托管时。事实证明,“来自邻居的辱骂性 I/O 尖峰”。在我引起他们的注意后,我的房东很快就解决了。

我的建议是了解您的基线/预期文件系统性能,停止 MySQL,并测量您的文件系统性能以确定是否存在更多与 MySQL 无关的基本问题。