什么是 buff/cache?
在 Linux 2.4
的内存管理中,buffer
指 Linux 内存的:Buffer cache
。cache
指 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
负责文件系统的缓存。
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
# 清除目录项和 inodeecho 3 > /proc/sys/vm/drop_caches
# 清除页面缓存、目录项以及 inode
但是这种放时只能在执行的当时起作用,过一段时间之后又会发现内存被占满,怎么办呢?
实际上内核提供了 vm.vfs_cache_pressure
参数用来控制缓冲区的回收频率,我们可以调整它。
这个参数是用来控制内核回收 VFS 缓存的频率。修改这个值会提高或者降低回收 VFS 缓存的频率。值可以设置为 0-200
中的任意值。越大回收频率越快,可以把 vm.vfs_cache_pressure
赋值为 200
来获得最快的回收频率。这个值默认值一般为 100
。
另外也可以使用 slabtop
分析内存使用情况。一般情况下,dentry
和 *_inode_cache
值越高回收的效果越好。
为什么是 dentry
和 *_inode_cache
呢,这是因为当读写文件时内核会为该文件对象建立一个 dentry
,并将其缓存起来,方便下一次读写时直接从内存中取出提高效率。
一些措施
内核参数
可以通过配置 vm.vfs_cache_pressure
参数,控制系统回收 directory entries 和 inode 缓存的倾向程度
Linux Kernel 文档描述如下:
此百分比值控制内核回收用于缓存directory
和inode
对象的内存的趋势。
在默认值vfs_cache_pressure=100
时,内核将尝试以pagecache
和swapcache
回收的“公平”速率回收dentry
和inode
。减小vfs_cache_pressure
会导致内核更倾向于保留dentry
和inode
缓存。当vfs_cache_pressure=0
时,由于内存压力,内核永远不会回收dentry
和inode
,这很容易导致内存不足的情况。将vfs_cache_pressure
增加到100
以上会导致内核更喜欢回收dentry
和inode
。
将vfs_cache_pressure
显著增加到100
以上可能会对性能产生负面影响。回收代码需要使用各种锁来查找可释放的目录和inode
对象。当vfs_cache_pressure=1000
时,它将查找比可用对象多 10 倍的可用对象。
可尝试将该值调整为 200
使得比默认值更积极地回收缓存,要持久化配置 vm.vfs_cache_pressure
为 200,
你可以通过以下几种方法:
- 通过 /etc/sysctl.conf 文件(推荐方法):
# 使用文本编辑器打开 /etc/sysctl.conf
sudo vim /etc/sysctl.conf
# 添加或修改以下行
vm.vfs_cache_pressure = 200
# 使配置生效
sudo sysctl -p
- 通过创建 /etc/sysctl.d/ 目录下的配置文件:
# 创建新的配置文件
sudo vim /etc/sysctl.d/99-vfs-cache-pressure.conf
# 添加以下行
vm.vfs_cache_pressure = 200
# 使配置生效
sudo sysctl --system
手动清理
$ sync
$ echo 1 > /proc/sys/vm/drop_caches
$ echo 2 > /proc/sys/vm/drop_caches
$ echo 3 > /proc/sys/vm/drop_caches
自动定时清理
不推荐这么做
1、创建脚本cleanCache.sh
#!/bin/bash#每两小时清除一次缓存
echo "开始清除缓存"
sync;sync;sync #写入硬盘,防止数据丢失
sleep 10#延迟10秒
echo 1 > /proc/sys/vm/drop_caches
echo 2 > /proc/sys/vm/drop_caches
echo 3 > /proc/sys/vm/drop_caches
2、创建定时任务
crontab -e #弹出配置文件
3、添加定时任务执行频率
#分 时 日 月 周 命令
0 */2 * * * /usr/local/bin/cleanCache.sh
4、设置crond启动以及开机自启
systemctl start crond.service
systemctl enable crond.service
5、查看定时任务是否被执行
cat /var/log/cron | grep cleanCache