MySQL MyISAM 磁盘绑定(bind)缩放问题/驱动器缓存

标签 mysql caching ubuntu disk myisam

我有以下查找表:

CREATE TABLE `widgetuser` (
 `widgetuserid` char(40) NOT NULL,
 `userid` int(10) unsigned NOT NULL,
 `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 PRIMARY KEY (`widgetuserid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 DELAY_KEY_WRITE=1;

我有一个结构相同但没有键的 widgetuser_tmp 表,我用这些数据(4mio 行)填充 widgetuser 表:

mysql> insert into widgetuser select * from widgetuser_tmp limit 0,4000000;flush tables;
Query OK, 4000000 rows affected (33.14 sec)
Records: 4000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (0.91 sec)

在写入时,它以 15MB/s 的速度直接进入 RAID-1,磁盘利用率 <50%,我们看不到任何读取,因为我用源表填充了磁盘缓存:

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00  3839.20    0.00   52.40     0.00    15.20   594.20    12.46  237.75   5.57  29.20
sdb               0.00  3839.00    0.00   52.60     0.00    15.20   591.94    14.50  275.59   7.19  37.80

我插入接下来的 1 Mio 行,一切正常,刷新后 wMB/s 立即回到 0:

mysql> insert into widgetuser select * from widgetuser_tmp limit 4000000,1000000;flush tables;
Query OK, 1000000 rows affected (10.18 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (0.87 sec)

mysql> insert into widgetuser select * from widgetuser_tmp limit 5000000,1000000;flush tables;
Query OK, 1000000 rows affected (10.21 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (1.02 sec)

mysql> insert into widgetuser select * from widgetuser_tmp limit 6000000,1000000;flush tables;
Query OK, 1000000 rows affected (10.67 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (1.17 sec)

但是当我执行 7mio 批处理时,结果看起来仍然相同,但是在 iostat -mdx sda sdb 5 中,突然我们有 100% util 30 秒:

mysql> insert into widgetuser select * from widgetuser_tmp limit 7000000,1000000;flush tables;
Query OK, 1000000 rows affected (10.73 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (1.21 sec)

Device:         rrqm/s   wrqm/s     r/s     w/s    rMB/s    wMB/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00    88.60    0.00  295.60     0.00     1.52    10.53   130.60  435.93   3.38 100.00
sdb               0.00    89.20    0.00  300.80     0.00     1.57    10.68   143.99  483.97   3.32 100.00

刷新后数据文件没有被触及:

-rw-rw---- 1 mysql mysql 1032000000 2009-10-30 12:10 widgetuser.MYD
-rw-rw---- 1 mysql mysql  522777600 2009-10-30 12:11 widgetuser.MYI  

而且表格状态接缝正常:

+----------------+--------+---------+------------+----------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+-------------------+---------+
| Name           | Engine | Version | Row_format | Rows     | Avg_row_length | Data_length | Max_data_length   | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time | Collation       | Checksum | Create_options    | Comment |
+----------------+--------+---------+------------+----------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+-------------------+---------+
| widgetuser     | MyISAM |      10 | Fixed      |  8000000 |            129 |  1032000000 | 36310271995674623 |    522777600 |         0 |           NULL | 2009-10-30 11:59:41 | 2009-10-30 12:10:59 | NULL       | utf8_general_ci |     NULL | delay_key_write=1 |         |
+----------------+--------+---------+------------+----------+----------------+-------------+-------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-----------------+----------+-------------------+---------+

当我继续时(因为我们有 100% 的驱动器利用率),它变得非常快:

mysql> insert into widgetuser select * from widgetuser_tmp limit 9000000,1000000;flush tables;
Query OK, 1000000 rows affected (31.93 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (2.34 sec)

mysql> insert into widgetuser select * from widgetuser_tmp limit 10000000,1000000;flush tables;
Query OK, 1000000 rows affected (2 min 39.72 sec)
Records: 1000000  Duplicates: 0  Warnings: 0
Query OK, 0 rows affected (7.82 sec)

检查主键以查看新条目是否唯一。一旦 key 不适合内存(key_buffer_size=512MB = ca.8Mio 条目),它需要从驱动器(-缓存)中获取丢失的 key 部分以进行检查。因此我们应该看到更多的读取和更慢的插入时间——我们没有看到更慢的读取,因为 key 被缓冲在磁盘缓存中。但我的问题是:谁突然写了这么多东西,在什么地方,为什么,我该如何解决这个问题?任何想法都会受到赞赏!

进一步的想法和见解:

  • 由于 1MB/s 的随机写入跟在完成的语句之后,因此已经通过了唯一性验证
  • 它是一个带有 ahci 的软件 raid-1,磁盘有 93% 空闲并且能够达到大约 80wMB/s
  • 机器有 8GB 内存,5GB 缓存,600MB 被 MySQL 使用,1.7GB 免费
  • MySQL 5.1.31-1ubuntu2-log
  • delay_key_write 不会改变这种行为
  • myisam_sort_buffer_size = 2 GB(虽然这里没有使用?)
  • key_buffer_size = 512 MB
  • bin_log 关闭
  • Linux 2.6.28-15-server #52-Ubuntu SMP Wed Sep 9 11:34:09 UTC 2009 x86_64 GNU/Linux

最佳答案

从您的问题中并不能完全清楚您期望或获得的行为是什么。这里有一些你可能不知道的事情

  • FLUSH TABLES 清除了 MyISAM 键缓存 - 它不仅写入脏 block ,还会丢弃干净 block ,因此必须再次获取每个索引 block 才能进行修改
  • MyISAM 默认使用 1k 的 block 大小,这可能小于您的文件系统 block ;这会造成性能问题
  • 如果您想要任何类型的持久性(您可能不会这样做,因为您使用的是 MyISAM),那么您应该在 Controller 中使用带有电池后备缓存的硬件 raid。

我的猜测是索引不再适合键缓冲区,或者它必须执行更多写入,这会触发读取,因为它们是未缓冲的写入 block 大小边界。

尝试将 myisam_block_size 更改为 4k 或更高并重建表(这是一个 my.cnf-only 选项,仅在重新启动后对新表生效)。

您可以使用 myisamchk -dv 检查表上的 block 大小

关于MySQL MyISAM 磁盘绑定(bind)缩放问题/驱动器缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1649458/

相关文章:

caching - 是什么导致 CPU 中的 L3 缓存未命中?

javascript - html 5 Web 应用程序缓存下载完整的 JavaScript 警报?

ubuntu - Maple Ubuntu 抗锯齿

linux - 从 Github 的私有(private)仓库中获取原始文件

bash - shell 脚本 : unexpected token ´if"

python - 在 python 中传递 le 或 ge 符号

php - 如何删除 SQL 查询中的重复条目? (我也可以用PHP实现)

php - PDO 预准备语句的功能不起作用并出现错误

c# - 如何初始化反射数据的线程安全静态缓存

php - PHP 中奇怪的关联数组行为