Buffer 和 Cache 的区别

从英语释义感受一下这俩不同的区别。

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

image.png

这样就能看到缓存了

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注