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

在 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):提供了每个进程的缓存命中情况

相关推荐
Hard but lovely2 小时前
Linux: posix标准:线程互斥&& 互斥量的原理&&抢票问题
linux·开发语言
漫漫求2 小时前
ubuntu设置软件开机自启动
linux·运维·ubuntu
Scholar With Saber2 小时前
kali Linux安装教程,ISO镜像安装(物理机,虚拟机皆可)kali安装2025最新,0基础可用,保姆级图文
linux·运维·网络安全
网硕互联的小客服2 小时前
哪些外在因素条件会导致服务器的延迟过高?
linux·运维·服务器·数据库·安全
wregjru2 小时前
【操作系统】2.用户和权限
linux·服务器·unix
甘韦2 小时前
CentOS 7更换阿里云的源
linux·阿里云·centos
写代码的学渣2 小时前
nmon下载安装使用方法
linux·运维
Lueeee.2 小时前
RTMP协议
linux·网络
吃不饱的得可可4 小时前
【Linux】System V消息队列与责任链模式
linux·运维·责任链模式