Linux buffer/cache

发布时间 2023-05-24 15:17:57作者: ArMinLi

在Linux系统中,经常用free命令来查看系统内存的使用状态。在一个centos7的系统上,free命令的显示内容大概是这样一个状态:

这里的默认显示单位是kb,可以通过添加-h参数,来让free 命令显示的更为友好一些。

[root@k8s-master-192 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G        663M         87M        2.1M        1.1G        995M
Swap:            0B          0B          0B

新版linux相对来说已经好很多了,在老版的时候,是没有available字段的。

什么是 buff/cache?

Buffer 是对磁盘(块)数据的缓存,而 Cache 是对文件(block)数据的缓存,他们既会用在读请求中,也会用的写请求中。

Linux 2.4 的内存管理中,buffer 指Linux内存的:Buffer cachecache指Linux内存中的:Page cache。一般呢,是这么解释两者的。

  • A buffer is someting that has yet to be ‘written’ to disk.
  • A cache is someting that has been ‘read’ from the disk and stored for later use.

翻译过来就是说:

  • buffer(buff) 是用来缓存尚未“写入”磁盘的内容。

  • cache 是用来缓存从磁盘“读取”出来的东西。

所以 buffer 被用来当成对io设备写的缓存。而 cache 被用来当作对io设备的读缓存。这里的io设备,主要指的是块设备文件和文件系统上的普通文件。

但是在 Linux 2.6 以后,它们的意义不一样了。

Linux 2.6 之后Linux将他们统一合并到了 Page cache 作为文件层的缓存。而 buffer 则被用作 block 层的缓存。

block 层的缓存是什么意思呢,可以认为一个 buffer 就是一个 physical disk block 在内存的代表,用来将内存中的 pages 映射为 disk blocks,这部分被使用的内存就叫做 buffer

buffer 里面的 pages,指的是 Page cache 中的 pages,所以,buffer也可以被认为Page cache的一部分。

简单来说,buffer 负责裸设备相关的缓存,cache 负责文件系统的缓存。

cache/buffers 是作为io设备的缓存存在的,目的是对io设备的访问进行加速。 比较好的策略是让它使用完所有的剩余内存,并在系统真正使用时再释放出来,这样可以尽可能的提高io设备的访问速度。 实际上目前linux的默认策略也是如此,会将剩余内存作为cache/buffers使用并在系统需要使用时自动释放出来。

Buffer 的具体职责

在当前的系统实现里,buffer 主要是设计用来在系统对块设备进行读写时作为缓存来使用。这意味着对块的操作会使用 buffer 进行缓存,比如在格式化文件系统的时候。

但是一般情况下两个缓存系统是一起配合使用的,比如当我们对一个文件进行写操作的时候,cache 的内容会被改变,而buffer则用来将cache 的 page 标记为不同的缓冲区,并记录是哪一个缓冲区被修改了。

这样,内核在后续执行脏数据的回写(writeback)时,就不用将整个 page 写回,而只需要写回修改的部分即可。

Cache 的具体职责

cache 主要用来作为文件系统上的文件数据的缓存来用,当进程对文件有 read/write 操作的时候。包括将文件映射到内存的系统调用 mmap ,就会用到 cache

因为 cache 被作为文件类型的缓存来用,所以事实上也负责了大部分的块设备文件的缓存工作。

回收 buff/cache

Linux内核会在内存将要耗尽的时候,会自动触发内存回收的工作,以便释放出内存给急需内存的进程使用。

但是这种回收的工作也并不是没有成本。

理解 cache 是干什么的就知道,cache 中存在着一部分 write 操作的数据。所以必须保证 cache 中的数据跟对应文件中的数据一致,才能对 cache 进行释放。

于是伴随着 cache 清除的行为的,一般都是系统 IO 飙高。这是因为内核要将 cache 中缓存的 write 数据进行回写。

可以使用下面这个文件来人工触发缓存清除的操作,Linux 提供了三种清空方式:

  • echo 1 > /proc/sys/vm/drop_caches # 仅清除页面缓存
  • echo 2 > /proc/sys/vm/drop_caches # 清除目录项和inode
  • echo 3 > /proc/sys/vm/drop_caches # 清除页面缓存、目录项以及inode

但是这种放时只能在执行的当时起作用,过一段时间之后又会发现内存被占满,怎么办呢?

实际上内核提供了 vm.vfs_cache_pressure 参数用来控制缓冲区的回收频率,可以调整它。

这个参数是用来控制内核回收VFS缓存的频率。修改这个值会提高或者降低回收VFS缓存的频率。值可以设置为 0-200 中的任意值。越大回收频率越快,可以把 vm.vfs_cache_pressure 赋值为200来获得最快的回收频率。这个值默认值一般为 100

buffer/cache测试

1、先看一下目前的内存使用量

[root@host01 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G         88M        1.5G        8.6M        179M        1.5G
Swap:          2.0G          0B        2.0G

2、生成一个文件测试一下

[root@host01 ~]# dd if=/dev/zero of=testfile bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 9.10893 s, 115 MB/s

3、检查一下内存的使用情况,是否和上面介绍的一样

4、手动执行一下释放,看能否将内存释放出来

[root@host01 ~]# echo 1 | tee /proc/sys/vm/drop_caches
1

# 可以看到 buff/cache 中的内存已经被释放掉
[root@host01 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G         88M        1.6G        8.6M         74M        1.6G
Swap:          2.0G          0B        2.0G

5、测试一下读取文件

[root@host01 ~]# time -p cat testfile > /dev/null
real 0.70
user 0.00
sys 0.75

6、可以看到用时 0.70s,在看下内存使用

[root@host01 ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           1.8G         89M        641M        8.6M        1.1G        1.5G
Swap:          2.0G          0B        2.0G

7、然后再次执行一下读取文件

[root@host01 ~]# time -p cat testfile > /dev/null
real 0.14
user 0.00
sys 0.15

可以看到用时缩短到了 0.14s,这里需要说明一下,由于这边是固态硬盘,所以差距没这么大,如果是机械硬盘的话差距会进一步扩大。