硬盘驱动器磁盘读取缓存
Posted
技术标签:
【中文标题】硬盘驱动器磁盘读取缓存【英文标题】:Hard drive on-disk read cache 【发布时间】:2017-01-27 20:36:06 【问题描述】:我知道硬盘驱动器(注意,我说的是磁性驱动器,而不是 SSD)具有内部磁盘 RAM 缓存。这些通常约为 64MB。我试图了解这些缓存的典型读取缓冲策略是什么。
天真地,我假设最新的读取被缓存了。我尝试使用 fio 以及我编写的一小段代码在辅助磁盘 Seagate ST32000645NS HDD 上进行简单测试。该磁盘甚至没有安装,因此不会干扰这些测试。两者都从磁盘缓冲区大小中包含的小范围扇区(几 MB)重复读取。两个测试都使用 O_DIRECT,以消除主机操作系统缓冲区的影响。由于现代磁盘接口具有 Gb/s 吞吐量,并且除了从磁盘的初始读取之外的所有内容都应该缓存在磁盘缓冲区中,我预计会看到 100s MB/s 的吞吐量。然而,我得到的结果只有 1MB/s,这表明磁盘上没有进行读取缓存。我什至尝试一遍又一遍地重复读取相同的 4KB,但仍然得到类似的糟糕结果。
我查看了 dmesg,上面写着“sd 1:0:0:0: [sdb] 写入缓存:启用,读取缓存:启用,不支持 DPO 或 FUA”。所以这里似乎没有配置问题。谁能在这里阐明磁盘读取缓存可能存在的问题?也许驱动程序中的一些底层默认配置告诉设备忽略读取缓存?
已编辑 - 这是相关的代码。
我连续多次运行的fio脚本代码:
[global]
bs=4k
rw=randread
random_generator=lfsr
direct=1
ioengine=libaio
iodepth=1
direct=1
[device]
filename=/dev/sdb
filesize=64M
size=64M
我的代码:
char name[20] = "/dev/sdb";
int fd = open(name, O_RDWR | O_DIRECT);
if (fd < 0)
printf("failed openning %s. errno %d\n", name, errno);
return -1;
int pagesize=getpagesize();
printf("pagesize %d\n", pagesize);
char* realbuff=malloc(4096+pagesize);
char* buf=((((int unsigned)realbuff+pagesize-1)/pagesize)*pagesize);
int res, off, total_reads = 100000;
for (i=0; i<total_reads;i++)
off = 0;
res = lseek(fd, off, SEEK_SET);
if (res != off)
printf("seek res %d, expected %d\n. i %d errno %d", res, off, i, errno);
close(fd);
return -1;
res = read(fd, buf, pagesize);
if (res != pagesize)
printf("read only %d bytes, expected %d\n. i %d errno %d", res, pagesize, i, errno);
close(fd);
return -1;
【问题讨论】:
你有什么理由使用O_RDWR
吗?如果你改用O_RDONLY
,你会得到类似的性能吗?
与 O_RDONLY 没有区别。我计划在将数据读取到磁盘之前先写入数据,所以我使用了 O_RDWR。
【参考方案1】:
通常,在小 I/O 大小上使用 O_DIRECT
性能较差,因此如果您想看到读取缓存的效果,请尝试发出大 I/O。分享fio
测试脚本或您的微基准代码以便能够为您提供帮助会很有帮助。
而且,您可以尝试在 hdparam
中设置预读选项,这在 this link 中有详细记录
----更新----
由于可以将直接 I/O 视为同步 I/O,因此必须在处理传入 I/O 之前完成 I/O。而且,小型 I/O 会占用大量时间来进行上下文切换和为 DMA 操作设置寄存器。
下图显示了直接 I/O 测试 fio 脚本的带宽。我使用提供的 fio 脚本将 I/O 大小从 4KB 更改为 8MB。它表明使用直接 I/O 发出小 I/O 大小的性能非常差,并且随着 I/O 大小的增加,性能也会提高。
由于直接 I/O 导致主机页面缓存无法工作,系统无法利用预读功能,并且必须从磁盘表面或设备上的磁盘缓存中获取数据,从而导致缓慢且繁琐的上下文切换.
【讨论】:
感谢您的帮助。我已经编辑了我的帖子以包含相关的代码片段(@paddy 你也要求这样做)。至于 O_DIRECT - 我可以理解为什么 O_DIRECT 对于小型随机访问的 HDD 上的小型读取会很慢。但是,如果读取的是缓冲数据,那这有什么关系呢? 注意:如果使用的 ioengine 是异步的,则直接 I/O 在 fio 中可以是异步的。当对块设备使用 ioengine=libaio --direct=1 --iodepth=16 时,您可以在 Linux 上看到这一点 - fio 在完成时报告的队列深度通常大于 1。【参考方案2】:增加深度、按顺序执行 I/O 和更改大小(更小和更大)是否会产生影响? Wikipedia suggests the hard disk's cache is only used for readahead/readbehind and write caching。如果是这样,即使您重新读取相同的区域,磁盘缓存在任何给定时间仅读取一个随机 I/O 也不会受益。
【讨论】:
以上是关于硬盘驱动器磁盘读取缓存的主要内容,如果未能解决你的问题,请参考以下文章