注册
测试linux页缓存对磁盘IO的影响
技术分享/ 文章详情 /

测试linux页缓存对磁盘IO的影响

codePanda 2025/12/31 160 0 0

在 Linux 系统中,页缓存(Page Cache) 是影响文件 I/O 性能最关键、也最容易被误解的机制之一。
很多人在使用 dd 测试磁盘性能时,看到“几 GB/s”的结果欣喜若狂,却忽略了一个事实:你测到的可能并不是磁盘,而是内存。

本文通过实验结合 **dd、pcstat 以及 bcc 工具集(cachestat、cachetop)**来测试页缓存对文件读写性能的真实影响。

一、Linux 页缓存:文件 I/O 的“加速器”

Linux 在进行文件 I/O 时,默认会使用页缓存:

读文件:第一次读取 → 磁盘 I/O,后续读取 → 直接从内存命中

写文件:默认先写入页缓存(脏页),再由内核异步刷盘

这意味着文件系统性能 ≠ 磁盘性能很多时候,看到的是“缓存性能”。

二、工具介绍

1、pcstat:查看指定文件在内核页缓存中的状态

root@panda:~# pcstat /bin/ls +---------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |---------+----------------+------------+-----------+---------| | /bin/ls | 126584 | 31 | 31 | 100.000 | +---------+----------------+------------+-----------+---------+

Cached 就是 /bin/ls 在缓存中的大小,而 Percent 则是缓存的百分比。如果是 0,这说明 /bin/ls 并不在缓存中。

2、cachestat(bc):提供了整个操作系统缓存的读写命中情况

cachestat 1 20 关键指标: ● TOTAL ,表示总的 I/O 次数; ● MISSES ,表示缓存未命中的次数; ● HITS ,表示缓存命中的次数; ● DIRTIES, 表示新增到缓存中的脏页数; ● BUFFERS_MB 表示 Buffers 的大小,以 MB 为单位; ● CACHED_MB 表示 Cache 的大小,以 MB 为单位。

3、cachetop(bc):提供了每个进程的缓存命中情况

默认按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命中情况。具体到每一个指标,

这里的 HITS、MISSES和DIRTIES ,跟 cachestat 里的含义一样,分别代表间隔时间内的缓存命中次数、未命中次数以及新增到缓存中的脏页数。而 READ_HIT 和 WRITE_HIT ,分别表示读和写的缓存命中率。类似 top可看到,哪个进程命中最多缓存,谁在制造大量 MISS,读写命中率(READ_HIT / WRITE_HIT)非常适合定位I/O 抖动、缓存争抢、性能异常进程

二、读场景:页缓存对读取性能的巨大提升

构造测试文件,先从磁盘读取一个 512MB 文件:

root@panda:~# dd if=/dev/sda1 of=file bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 2.853 s, 188 MB/s

输出结果:536870912 bytes (537 MB, 512 MiB) copied, 2.853 s, 188 MB/s,这是典型的磁盘读取速度

清理页缓存,模拟“首次访问”

root@panda:~# echo 3 > /proc/sys/vm/drop_caches

查看文件缓存状态:

root@panda:~# pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 0 | 0.000 | +-------+----------------+------------+-----------+---------+

说明文件完全不在页缓存中。

观察指标

第一个终端,每隔5秒刷新一次数据

cachetop 5

第一次读取文件(磁盘 I/O)

第二个终端

root@panda:~# dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.583242 s, 920 MB/s

速度已经有所提升(顺序读 + 预读)。再次执行刚才的 dd 命令

第二次、第三次读取(缓存命中)

root@panda:~# dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.118244 s, 4.5 GB/s <<<<< root@panda:~# dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.0774348 s, 6.9 GB/s root@panda:~# dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.0791728 s, 6.8 GB/s root@panda:~# dd if=file of=/dev/null bs=1M 512+0 records in 512+0 records out 536870912 bytes (537 MB, 512 MiB) copied, 0.0791668 s, 6.8 GB/s

关键结论:文件一旦完全进入页缓存,读取性能可以从百 MB/s → 数 GB/s

再次确认缓存状态:

root@panda:~# pcstat file +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | file | 536870912 | 131072 | 131072 | 100.000 | +-------+----------------+------------+-----------+---------+

结论一:页缓存显著提高文件读取性能

第一次读受磁盘 I/O 限制,后续读完全命中页缓存,速度接近内存带宽,dd 读测试极易被缓存“欺骗”。

三、写入场景:同步写入 vs 缓存写入

同步写入(oflag=dsync)

root@panda:~# dd if=/dev/zero of=file bs=32k count=20000 oflag=dsync ^C794+0 records in 794+0 records out 26017792 bytes (26 MB, 25 MiB) copied, 7.43446 s, 3.5 MB/s

每次写入都需要等待数据真正落盘,没有写合并和异步刷盘,性能极低,但**非常真实,**可以用来模拟数据库commit落盘时真实的写入性能。

同步写入后,页缓存是否存在?

root@panda:~# pcstat test +-------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |-------+----------------+------------+-----------+---------| | test | 33751040 | 8240 | 8240 | 100.000 | +-------+----------------+------------+-----------+---------+

说明即使是 dsync文件内容仍然会进入页缓存,只是写入路径变慢。

普通写入(默认缓存写)

去掉 oflag=dsync 直接IO

root@panda:~# dd if=/dev/zero of=test bs=32k count=20000 20000+0 records in 20000+0 records out 655360000 bytes (655 MB, 625 MiB) copied, 0.846184 s, 774 MB/s root@panda:~# root@panda:~# dd if=/dev/zero of=file bs=32k count=20000 20000+0 records in 20000+0 records out 655360000 bytes (655 MB, 625 MiB) copied, 0.857168 s, 765 MB/s

这是典型的写入页缓存,异步刷盘,测到的是内存写性能

结论二:同步写入显著降低写性能

oflag=dsync / sync:写入真实磁盘性能,吞吐量明显下降

默认写入:极高吞吐,并不等价于磁盘能力

四、缓存让性能测试“严重失真”

很多人用:

dd if=/dev/zero of=file dd if=file of=/dev/null

来测试磁盘性能,但如果不清缓存,不使用 O_DIRECT,那么测试的结果本质是:内存 → 内存

正确测试磁盘性能的方式:

1、清理缓存

echo 3 > /proc/sys/vm/drop_caches

2、或绕过页缓存

oflag=direct / iflag=direct

3、测试数据库commit落盘写入性能

oflag=dsync

五、实验总结

1、页缓存显著提高文件读取性能

文件第一次读取时,由于磁盘 I/O 限制,速度相对较慢。文件再次读取时,由于页缓存命中,速度可提升数倍至数十倍(甚至达到 GB/s 级别),大大提高文件访问效率。但同时也要注意,如果我们把 dd 当成测试文件系统性能的工具,由于缓存的存在,就会导致测试结果严重失真。

2、I/O 性能测试需谨慎,同步写入(dsync/sync)会降低写入速度

每次写入直接落盘会明显降低写入吞吐,但缓存仍可用于后续读取加速,IO慢可以查找是否是直接IO问题或者用dd直接IO模拟真实磁盘读写性能。缓存会导致 dd 或其他工具测试文件系统性能时出现严重失真。若想测试磁盘实际性能,缓存清理或使用 oflag=direct/O_DIRECT 来绕过页缓存。

3、清理缓存会恢复文件到未缓存状态

echo 3 > /proc/sys/vm/drop_caches 可清空页缓存,模拟首次磁盘访问场景。

4、缓存状态可通过工具实时监控

pcstat:查看指定文件在内核页缓存中的状态

cachestat(bc):提供了整个操作系统缓存的读写命中情况

cachetop(bc):提供了每个进程的缓存命中情况

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服