我有一个 30TB 大小的硬件 RAID-6 系统 (LSI 9280-8e),由 10 个 DC-S4500 Intel SSD 组成,用于数据库。操作系统 Debian 7.11,内核 3.2。文件系统是 XFS,使用 nobarrier 选项挂载。
看到随机 I/O 性能与我的预期相比有些迟缓,我开始通过运行 fio 基准测试来调查发生了什么。令我惊讶的是,当我在随机读取设置(iodepth=32 和 ioengine=libaio)下对 1Tb 文件使用 fio 时,我得到了 ~ 3000 IOPS,这比我预期的要低得多。
random-read: (groupid=0, jobs=1): err= 0: pid=128531
read : io=233364KB, bw=19149KB/s, iops=4787 , runt= 12187msec
...
cpu : usr=1.94%, sys=5.81%, ctx=58484, majf=0, minf=53
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=99.9%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued : total=r=58341/w=0/d=0, short=r=0/w=0/d=0
但是如果我使用 direct=1 选项(即绕过 linux 的缓冲区缓存),我会得到 ~ 40000 IOPS,这是我想要看到的。
random-read: (groupid=0, jobs=1): err= 0: pid=130252
read : io=2063.7MB, bw=182028KB/s, iops=45507 , runt= 11609msec
....
cpu : usr=6.93%, sys=23.29%, ctx=56503, majf=0, minf=54
IO depths : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=100.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued : total=r=528291/w=0/d=0, short=r=0/w=0/d=0
我似乎已经以调度程序、预读和旋转设置的形式对 SSD 分区进行了所有正确的设置。
root@XX:~# cat /sys/block/sdd/queue/scheduler
[noop] deadline cfq
root@XX:~# cat /sys/block/sdd/queue/rotational
0
root@XX:~# blockdev --getra /dev/sdd
0
我是否还遗漏了导致缓冲性能大幅降低的原因?还是预计 DIRECT 与缓冲之间存在如此大的差异?
我还查看了两次运行期间的 iostat 输出,这是在使用 direct=1 时的情况:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sdd 0.00 0.00 48110.00 0.00 192544.00 0.00 8.00 27.83 0.58 0.58 0.00 0.02 99.60
这是一个缓冲运行
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sdd 0.00 0.00 4863.00 0.00 19780.00 0.00 8.13 0.89 0.18 0.18 0.00 0.18 85.60
因此,看起来关键的区别在于队列大小 (avgqu-sz),当使用缓冲 I/O 时,该大小很小。考虑到 nr_requests 和queue_depth 都很高,我觉得这很奇怪:
root@XX:~# cat /sys/block/sdd/queue/nr_requests
128
root@XX:~# cat /sys/block/sda/device/queue_depth
256
这里有什么建议吗?
答案1
带有 3.2 内核的 Debian 7.11
如果可能的话,请升级。您不仅会获得内核改进,而且 Wheezy 的生命周期也将结束。
是的,当 direct=1 时,您会看到更高的利用率和队列深度。fio 手册特别提到了这种情况(重点是我的):
io深度=int
针对文件保持飞行状态的 I/O 单元数。请注意,将 iodepth 增加到 1 以上不会影响同步 ioengines(使用 verify_async 时的小程度除外)。即使是异步引擎也可能施加 OS 限制,导致无法实现所需的深度。当使用 libaio 并且未设置 direct=1 时,Linux 上可能会发生这种情况,因为该操作系统上的缓冲 I/O 不是异步的。密切关注 fio 输出中的 I/O 深度分布,以验证实现的深度是否符合预期
因此,libaio 需要 O_DIRECT 才能实现异步,这是一个需要了解的重要实现细节。有人问,不直接使用 libaio 是否是个好主意:
使用 libaio 时设置 direct=0 是否有效?
你可以这样做,但我不建议这样做。在当今的 Linux 内核中,如果没有 O_DIRECT,libaio 提交很可能会变成阻塞(因此不再是异步的),这会限制实现的并行 I/O 数量。有强有力的论据表明,fio 示例不应鼓励这种选项组合...
手册文档中的“排队”行为是什么意思?
如果你指的是“请注意,Linux 可能仅支持非缓冲 I/O 的排队行为”(在 http://fio.readthedocs.io/en/latest/fio_doc.html#io-engine)我认为它试图表达的是:
“当使用 direct=1 和 libaio 时,您可以提交一个 I/O 并让内核将其异步排队,从而允许提交系统调用立即返回,并为您提供在 I/O 完成之前排队其他提交的机会,而不是阻塞提交系统调用直到 I/O 关闭并从最低的磁盘设备返回(阻塞行为)。
还可以尝试使用 ioengine=psync 和 direct=0 进行控制测试。即使使用缓存进行同步写入也可以实现大量 IOPS。
所有这些都回避了真正的问题:您正在运行的数据库工作负载存在什么问题?问题症状、软件版本、配置、性能指标(iostat)。DBMS 的 I/O 实现可能与您模拟的、使用的系统调用、执行 I/O 的多个文件和作业等任何事情大不相同。如果您想进一步调查,这是一个值得思考的问题。