从英语释义感受一下这俩不同的区别。
Buffer /'bʌfə/ [计] 缓冲区;缓冲器,[车辆] 减震器
Cache /kæʃ/ 没错读 /kæʃ/ 不是 /ketʃ/ 。缓存。
Buffers 是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB 左右)。这样,内核就可以把分散的写集中起来,统一优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。
Cached 是从磁盘读取文件的页缓存(page cache),也就是用来缓存从文件读取的数据 这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。
来进行一个实验:
用dd命令来模拟磁盘和文件i/o,
1 清除文件页,目录项,Inodes等缓存。
echo 3 > /proc/sys/vm/drop_caches
2 打开两个终端
在一个终端里面 vmstat 1 每一秒打印一组数据
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 407004 2964 40000 0 0 7 9 73 141 0 0 100 0 0
主要看 buff cache bi bo这四个参数.bi 是块设备读取,bo是块设备写入。
在另外一个终端里,用dd命令写入文件 500M dd if=/dev/urandom/ of=/tmp/file bs=1M count=500
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 407020 2972 40004 0 0 7 9 73 141 0 0 100 0 0
0 0 0 407004 2972 40012 0 0 0 0 71 151 0 0 100 0 0
0 1 0 406600 3380 40020 0 0 408 0 98 152 0 0 95 5 0
0 0 0 406352 3636 40012 0 0 256 0 104 160 0 0 99 1 0
1 0 0 405840 3704 40152 0 0 124 0 100 209 0 2 98 0 0
1 0 0 367640 3708 77024 0 0 4 28700 357 150 0 100 0 0 0
1 0 0 330860 3724 112872 0 0 4 36864 438 176 0 100 0 0 0
1 0 0 303348 3732 139500 0 0 0 32 344 148 0 100 0 0 0
1 0 0 294016 3732 148616 0 0 0 28760 396 162 0 100 0 0 0
1 0 0 265512 3732 176372 0 0 0 36864 380 171 0 100 0 0 0
1 0 0 227648 3744 213264 0 0 4 28688 365 180 0 99 0 1 0
1 0 0 208812 3752 231668 0 0 0 32 312 160 0 100 0 0 0
1 0 0 199300 3752 240892 0 0 0 35840 376 183 0 100 0 0 0
1 0 0 161436 3760 277748 0 0 0 28716 361 185 0 100 0 0 0
1 0 0 133312 3760 305404 0 0 4 35840 377 183 0 100 0 0 0
1 0 0 96348 3772 341280 0 0 4 28696 361 166 0 99 0 1 0
1 0 0 67920 3780 368932 0 0 0 35364 386 186 0 100 0 0 0
1 0 0 72376 2672 365692 0 0 0 28692 370 186 0 100 0 0 0
1 0 0 65272 2680 372708 0 0 0 36348 377 163 0 100 0 0 0
1 0 0 69988 2316 368304 0 0 4 28700 376 171 0 100 0 0 0
2 0 0 63132 2088 375324 0 0 0 35840 365 164 0 100 0 0 0
1 0 0 68380 1596 370844 0 0 0 28696 364 152 0 100 0 0 0
1 0 0 80340 1332 359416 0 0 0 0 323 168 0 100 0 0 0
0 0 0 72596 1340 367568 0 0 16 29724 345 216 0 78 22 0 0
0 0 0 72604 1340 367584 0 0 0 0 95 178 0 0 100 0 0
cache 在逐渐增大,bi (块设备读取)在短暂的增长之后就退台了。只出现一次408kb/s
bo 一直在保持在增长状态, bo 大于零的。说好的cache 是用来缓存读文件的,怎么写也会影响到cache?
再来看一看往硬盘里写2G内容(如果就一块磁盘不要尝试这个命令。),
echo 3 > /proc/sys/vm/drop_caches
dd if=/dev/urandom of=/dev/sdb1 bs=1M count=2048
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 7584780 153592 97436 0 0 684 0 31 423 1 48 50 2 0
1 0 0 7418580 315384 101668 0 0 0 0 32 144 0 50 50 0 0
1 0 0 7253664 475844 106208 0 0 0 0 20 137 0 50 50 0 0
1 0 0 7093352 631800 110520 0 0 0 0 23 223 0 50 50 0 0
1 1 0 6930056 790520 114980 0 0 0 12804 23 168 0 50 42 9 0
1 0 0 6757204 949240 119396 0 0 0 183804 24 191 0 53 26 21 0
1 1 0 6591516 1107960 123840 0 0 0 77316 22 232 0 52 16 33 0
buf在疯狂的增长,cache也在缓慢增长。 in系统中断次数也不停的在涨。
对比两个案例,我们发现,写文件时会用到 Cache 缓存数据,而写磁盘则会用到 Buffer 来缓存数据。所以,回到刚刚的问题,虽然文档上只提到,Cache 是文件读的缓存,但实际上,Cache 也会缓存写文件时的数据。
写完了我们再来读取文件。
echo 3 > /proc/sys/vm/drop_caches
dd if=/tmp/file of=/tmp/null
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 1 0 7724164 2380 110844 0 0 16576 0 62 360 2 2 76 21 0
0 1 0 7691544 2380 143472 0 0 32640 0 46 439 1 3 50 46 0
0 1 0 7658736 2380 176204 0 0 32640 0 54 407 1 4 50 46 0
0 1 0 7626052 2380 208908 0 0 32640 40 44 422 2 2 50 46 0
读取文件的时候,cache在疯狂的增长,buff基本不变。
读完文件再来测试读取磁盘
# 首先清理缓存
$ echo 3 > /proc/sys/vm/drop_caches
# 运行 dd 命令读取文件
$ dd if=/dev/sda1 of=/dev/null bs=1M count=1024
执行 vmstat 1
rocs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 422860 900 28092 0 0 34 19 74 142 0 0 100 0 0
0 0 0 422768 900 28176 0 0 80 0 77 143 0 0 100 0 0
0 0 0 422768 900 28176 0 0 0 0 69 139 0 1 99 0 0
0 0 0 422768 900 28176 0 0 0 0 69 142 0 0 100 0 0
1 0 0 405032 9588 36740 0 0 8744 0 159 191 1 5 91 3 0
1 0 0 230620 94588 121652 0 0 85000 86064 964 257 6 42 0 52 0
0 1 0 78132 159168 204988 0 0 84868 57368 970 230 8 41 0 51 0
0 1 0 77884 159296 205152 0 0 128 0 69 152 0 0 0 100 0
1 1 0 75460 103412 263380 0 0 58328 86060 743 339 1 33 0 66 0
1 0 0 61780 91984 288664 0 0 99460 93148 1218 389 7 52 0 41 0
1 0 0 74344 85532 282316 0 0 148920 143420 1733 462 14 77 0 9 0
1 0 0 61612 91868 288688 0 0 139600 143420 1659 422 6 81 0 12 0
1 0 0 75780 85640 280668 0 0 148816 143420 1758 459 11 77 0 12 0
0 1 0 73628 87384 280656 0 0 49156 57368 646 520 3 26 0 71 0
0 1 0 73128 85992 282980 0 0 28260 28732 396 353 2 15 0 83 0
0 1 0 81224 83620 277136 0 0 18052 0 224 328 1 10 0 89 0
0 1 0 80952 83964 277188 0 0 11264 35972 241 280 1 5 0 94 0
读取磁盘的时候 buffer 是在疯狂的增长,cache也在增长。
总结:
从写的角度来说,不仅可以优化磁盘和文件的写入,对应用程序也有好处,应用程序可以在数据真正落盘前,就返回去做其他工作。
从读的角度来说,既可以加速读取那些需要频繁访问的数据,也降低了频繁 I/O 对磁盘的压力。
那么如何查看这些缓存的命中率呢?
来安装这些之前 先要安装bcc
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)
操作完这些步骤,bcc 提供的所有工具就都安装到 /usr/share/bcc/tools 这个目录中了。自己手动配置到系统的 PATH 路径中,:
export PATH=$PATH:/usr/share/bcc/tools
cachestat 提供了整个操作系统缓存的读写命中情况。
cachestat 1 3
TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB
2 0 2 1 17 279
2 0 2 1 17 279
2 0 2 1 17 279
TOTAL 总的io次数
MISSES 缓存未命中次数
HITS 缓存命中次数
DIRTIES 脏页数
BUFFERS_MB buffer的大小 单位是MB
CACHED_MB cache的大小 单位是MB
cachetop 提供了每个进程的缓存命中情况。
cachetop
11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%
13029 root python 1 0 0 100.0% 0.0%
而 READ_HIT 和 WRITE_HIT ,分别表示读和写的命中率。
查询 指定文件的缓存
pcstat 可以用来查询指定文件的缓存
它是一个以go为基准的开发工具
wget https://dl.google.com/go/go1.12.5.linux-amd64.tar.gz 下载go语言
tar -zxvf go1.12.5.linux-amd64.tar.gz 解压缩
export GOPATH=~/go
export PATH=~/go/bin:$PATH
go get golang.org/x/sys/unix
go get github.com/tobert/pcstat/pcstat
然后执行 pcstat /bin/ls
pcstat /bin/ls
+-----------+----------------+------------+-----------+-----------+
| Name | Size (bytes) | Pages | Cached | Percent |
|------------+----------------+------------+-----------+---------|
| /bin/ls | 133792 | 33 | 0 | 000.000 |
+---------+----------------+------------+-----------+---------+
Percent 缓存百分比0,这说明 /bin/ls 并不在缓存中。
先来执行一下ls
然后执行 pcstat /bin/ls
这样就能看到缓存了