1、缓存命中率
使用 bcc 软件包,基于 Linux 内核 eBPF(extended Berkeley Packet Filters)机制,来跟踪内核中管理的缓存,并输出缓存的使用和命中情况。
- cachestat:提供了整个操作系统缓存的读写命中情况
-
1、安装 bcc
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDDecho "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.listsudo apt-get updatesudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)
命令导入PATH路径
export PATH=$PATH:/usr/share/bcc/tools
2、cachestat

HITS:表示缓存命中的次数
- MISSES:表示缓存未命中的次数
- DIRTIES:表示新增到缓存中的脏页数
- HITRATIO:以百分比表示的命中率
- BUFFERS_MB:表示 Buffers 的大小,以MB为单位
-
3、cachetop

默认按照缓存的命中次数(HITS)排序 HITS:代表间隔时间内的缓存命中次数
- MISSES :代表未命中次数,单位是 页
-
2、指定文件的缓存大小
使用
pcstat来查看文件在内存中的缓存大小以及缓存比例1、pcstat
1、安装
pcstat 是一个基于 Go 语言开发的工具,需要先安装 go 语言
export GOPATH=~/goexport PATH=~/go/bin:$PATHgo get golang.org/x/sys/unixgo get github.com/tobert/pcstat/pcstat

所以这里推荐直接源码安装,然后根据报错信息,手动设置包路径即可mkdir -p $GOPATH/src/golang.org/x/cd !$git clone https://github.com/golang/sys.gitgit clone https://github.com/golang/text.git
git clone https://github.com/tobert/pcstat.gitcd pcstatgo buildsudo cp -a pcstat /usr/local/binpcstat /usr/local/bin/pcstat
2、使用

Cached:就是 /bin/ls 在缓存中的大小
-
3、命中缓存demo
# 生成一个512MB的临时文件dd if=/dev/sda1 of=file bs=1M count=512# 清理缓存echo 3 > /proc/sys/vm/drop_caches
1、第一次读取
运行 dd 命令测试文件的读取速度

发现性能只有 524 MB/s,因为我这里是固态,所以比机械磁盘要快好多。
然后查看cachetop缓存命中情况,发现缓存命中率只有 49.9% 。
2、缓存命中
再次执行读取文件,可以看到速度直接到了 5 GB/s,缓存命中也达到了 100%

4、demo
1、准备
镜像,参数支持:
d 选项,设置要读取的磁盘或分区路径,默认是查找前缀为 /dev/sd 或者 /dev/xvd 的磁盘。
- -s 选项,设置每次读取的数据量大小,单位为字节,默认为 33554432(也就是 32MB)。
docker run --privileged --name=app -itd feisky/app:io-direct
2、分析
可以看到,每读取 32 MB 的数据,就需要花费 0.02s 的时间,比较慢。

但是可以看出已经全部走缓存了。
这里需要注意,每秒实际读取的数据大小。HITS 表示缓存的命中次数。每次命中读取 一页 数据。
内存以页为单位管理。每 页 的大小是 4KB,在 5s 的时间间隔里,命中缓存为 10244K/1024 = 4MB,再除以 5s,得出 每秒读的缓存是 0.8MB,跟32MB还是差很多的。
通过 strace 结果可以看到,案例应用了 openat 来打开磁盘分区 /dev/sda3,并且传入参数。
O_RDONLY 表示以只读方式打开,而 *O_DIRECT 则表示以直接读取的方式打开,这会绕过系统的缓存。
这也就是耗时的原因。
查看源码,发现
确实直接使用了 直接 I/O 。需要删除 O_DIRECT 选项。int flags = O_RDONLY | O_LARGEFILE | O_DIRECT;int fd = open(disk, flags, 0755);

