大量未读和要刷新的页面

Dav*_* R. 5 mysql innodb

我正在为 Moodle 安装运行一个 mysql 数据库后端,几个月后性能确实开始受到影响(某些页面加载时间长达 30 秒)。在 InnoDB 缓冲池中调查时,我发现缓冲池大小似乎是正确的(innodb_buffer_pool_wait_free = 0)。但是,我还发现我的读取未命中率 (52%) 非常高,而且要刷新的页面数量似乎相当多(3100 万)。我目前正在运行慢查询日志,但是页面加载的延迟似乎太多了,不能仅仅来自未优化的查询。

我一直无法找到任何解释为什么这两者都如此之高。有没有人解释为什么 Read Misses 和 Pages To Be Flushed 会有这些结果?

更新:我在预定的停机期间每周重新启动服务器。我仍然无法想象为什么这会变得如此之大。没有内置自动刷新机制吗?

Rol*_*DBA 3

真正令我震惊的是 52% 的失误率。您的innodb_buffer_pool_size可能太小了。

请记住,InnoDB 缓冲池会缓存数据页和索引页。

怎样才能得到合适的尺寸呢?运行此查询:

SELECT
    CONCAT(CEILING(ibps/POWER(1024,1)),'K') IBPS_KB,
    CONCAT(CEILING(ibps/POWER(1024,2)),'M') IBPS_MB,
    CONCAT(CEILING(ibps/POWER(1024,3)),'G') IBPS_GB
FROM (SELECT SUM(data_length+index_length) ibps
FROM information_schema.tables WHERE engine='InnoDB') A;
Run Code Online (Sandbox Code Playgroud)

这会给你这样的东西

mysql> SELECT
    ->     CONCAT(CEILING(ibps/POWER(1024,1)),'K') IBPS_KB,
    ->     CONCAT(CEILING(ibps/POWER(1024,2)),'M') IBPS_MB,
    ->     CONCAT(CEILING(ibps/POWER(1024,3)),'G') IBPS_GB
    -> FROM (SELECT SUM(data_length+index_length) ibps
    -> FROM information_schema.tables WHERE engine='InnoDB') A;
+-----------+---------+---------+
| IBPS_KB   | IBPS_MB | IBPS_GB |
+-----------+---------+---------+
| 30333520K | 29623M  | 29G     |
+-----------+---------+---------+
1 row in set (11.43 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

如果输出提供的设置超过数据库服务器已安装 RAM 的 80%,则使用已安装 RAM 的 80% 作为innodb_buffer_pool_size

试一试 !!!

更新 2013-04-15 12:43(美国东部时间)

我们来看看它的定义Innodb_buffer_pool_wait_free

通常,对 InnoDB 缓冲池的写入发生在后台。但是,如果需要读取或创建页面,而没有可用的干净页面,则也需要先等待页面被刷新。该计数器对这些等待的实例进行计数。如果缓冲池大小设置得当,这个值应该很小。

如前所述,如果buffer pool size has been set properly, this value should be small. 您可能只是在缓冲池中有大量需要刷新到磁盘的脏页。您应该监视Innodb_buffer_pool_pages_dirty

您可以采取两件事来改善这种情况:

改进#1:升级到最新的 MySQL

我信任 MySQL 5.5。我有一个客户即将使用 MySQL 5.6.10。我也相信它。这些版本的 MySQL 具有 InnoDB 插件标准。它们更有效地刷新脏页。

您还可以调整 InnoDB。在MySQL 5.1下,有4个读IO线程和4个写IO线程。MySQL 5.5+ 允许您增加这些以获得更好的 InnoDB 读写性能。InnoDB For MySQL 5.5.+ 可以访问多个CPU/核心。如果使用 MySQL 5.1.38+ 并且安装了 InnoDB 插件,MySQL 5.1 可以做到这一点(恕我直言,太混乱了,请使用 MySQL 5.5/5.6)。MySQL 5.1.27 无法执行此操作。

改进#2:更频繁地刷新脏页

您可以立即执行此操作

SET GLOBAL innodb_max_dirty_pages_pct = 0;
Run Code Online (Sandbox Code Playgroud)

MySQL 5.1 中innodb_max_dirty_pages_pct的默认值为90。将其降至零 (0)。然后,开始观察Innodb_buffer_pool_pages_dirty。在繁忙的写入服务器上,这应该下降到Innodb_buffer_pool_pages_total的 1% 。