缓存命中率
这里的缓存指的是数据在内存中的临时存储
缓存命中率:指直接通过缓存获取数据的请求次数,占所有数据请求次数的百分比。命中率越高,表示使用缓存带来的收益越高,应用程序的性能也就越好
一、工具介绍
1. cachestat 和 cachetop
- cachestat:提供了整个操作系统缓存的读写命中情况
- cachetop:提供了每个进程的缓存命中情况
这两个工具都是 bbc 软件包的一部分,基于 Linux 内核的 eBPF(extended Berkeley Packet Filters)机制,来跟踪内核中管理的缓存,并输出缓存的使用和命中情况。bbc-tools 需要内核为 4.1 或者更新的版本。
安装:这个库提供了编译好的二进制:https://github.com/brendangregg/perf-tools
cachestat 的使用,以 1 秒的时间间隔输出:
1 | ➜ [/tmp] cachestat 1 |
- HITS:表示缓存命中的次数
- MISSES:表示缓存未命中的次数
- DIRTIES:表示新增到缓存中的脏页数
- RATIO:缓存命中率,表示
HITS / (HITS + MISSES)
的值 - BUFFERS_MB:表示 Buffers 的大小,以 MB 为单位
- CACHE_MB:表示 cache 的大小,以 MB 为单位
cachetop 的使用:
1 | cachetop |
cachetop 默认会按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命中情况。字段含义和 cachestat 一样;READ_HIT 和 WRITE_HIT 分别表示读和写的缓存命中率。
2. pcstat
安装( x86_64 系统): curl -L -o pcstat https://github.com/tobert/pcstat/raw/2014-05-02-01/pcstat.x86_64
作用:查看文件在内存中的缓存大小以及缓存比例
1 | ➜ [/usr/local] pcstat /bin/perf |
如上,Cached 就是 /bin/perf 在缓存中的大小,Percent 则是缓存的百分比。如果为 0 表示不在缓存中;之后我们使用了 perf 命令,就会发现 perf 已经在缓存中
二、案例场景
1. 文件被缓存前和缓存后的读取速度
使用 dd 命令生成一个临时文件
1
2
3
4生成一个512MB的临时文件
dd if=/dev/sda1 of=file bs=1M count=512
清理缓存
echo 3 > /proc/sys/vm/drop_caches执行 pcstat ,确认刚刚生成的文件不在缓存中。
1
2
3
4
5
6➜ [/tmp] pcstat file
|----------+----------------+------------+-----------+---------|
| Name | Size | Pages | Cached | Percent |
|----------+----------------+------------+-----------+---------|
| file | 536870912 | 131072 | 0 | 000.000 |
|----------+----------------+------------+-----------+---------|执行
cachetop 5
命令每 5 秒刷新一次数据在其他终端运行 dd 命令测试文件的读取速度。可以看到,这个文件的读取性能是 123 MB/s,由于 dd 命令运行之前我们清理了缓存,因此 dd 命令在读取数据时,肯定要通过文件系统从磁盘中读取。
1
2
3
4➜ [/tmp] dd if=file of=/dev/null bs=1M
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 4.37107 s, 123 MB/s回去看一下
cachetop
的终端,查看进程缓存命中情况。并不是所有的读都落到了磁盘,读请求的缓存命中率只有 50%1
2
3PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%
\.\.\.
3264 root dd 37077 37330 0 49.8% 50.2%此时看一下
pcstat file
,这个文件已经全部缓存在内存中1
2
3
4
5
6➜ [/tmp] pcstat file
|----------+----------------+------------+-----------+---------|
| Name | Size | Pages | Cached | Percent |
|----------+----------------+------------+-----------+---------|
| file | 536870912 | 131072 | 131072 | 100.000 |
|----------+----------------+------------+-----------+---------|再次执行 dd 命令,可以看到读性能变成了 6.6 GB/s 。说明是从缓存中读取的。
1
2
3
4➜ [/tmp] dd if=file of=/dev/null bs=1M
512+0 records in
512+0 records out
536870912 bytes (537 MB) copied, 0.0808783 s, 6.6 GB/s在看一下 cachetop 的终端,读的缓存命中率是 100%,也就是说这次的 dd 命令全部命中了缓存,所以性能特别高
1
2
3
410:45:22 Buffers MB: 4 / Cached MB: 719 / Sort: HITS / Order: ascending
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%
\.\.\.
32642 root dd 131637 0 0 100.0% 0.0%
结论:系统缓存对第二次 dd 操作有明显的加速效果,可以大大提高文件读取的性能。但是同时也要注意如果用 dd 当成测试文件系统性能的工具,由于缓存的存在,会导致测试结果严重失真,每次 dd 的时候需要先清理缓存 echo 3 > /proc/sys/vm/drop_caches
2. 使用 direct IO
1 | int flags = O_RDONLY | O_LARGEFILE | O_DIRECT; |
如上打开文件的方式使用了直接 IO,这样会绕过系统的缓存。我们可以观察 cachetop 中某个进程命中的次数
1 | 16:39:18 Buffers MB: 73 / Cached MB: 281 / Sort: HITS / Order: ascending |
如上所示,HITS 为 1024,说明缓存的命中次数为 1024,每次命中会读取一页,内存以页为单位进行管理,而每个页的大小是 4KB。假如整个读取过程是 5 秒,因此,在 5 秒的时间间隔里,命中的缓存为 1024 * 4K = 4MB
,再除 5 秒,可以得到每秒读的缓存是 0.8 MB。
接下来,可以使用 strace 来看下程序执行过程中系统调用来确认程序的那部分出现问题。
注意:cachetop 工具并不把直接 IO 算进来,因此如果使用直接 IO 的话,不会看到大量数据的未命中情况
注意:直接 IO 是跳过 buffer,裸 IO 是跳过文件系统(还是有 buffer 的)
注意:如上使用直接 IO,但还是有 100% 缓存命中率,因为还有元数据缓存