Linux 缓存优化
Linux 中的文件系统缓存是一种机制,它允许内核将经常访问的数据存储在内存中,以便更快地访问。内核使用页面缓存来存储最近从文件读取的数据,和文件系统的元数据。
例如,当一个程序从一个文件中读取数据时,内核会执行以下几项任务:
检查页面缓存以查看数据是否已在内存中。
如果数据在内存中,内核只是从缓存中返回数据。
否则,它会从存储驱动器读取数据,并将其副本存储在缓存中以供将来使用。
此外,内核还使用 dentries 缓存来存储有关文件系统对象的信息。这些文件系统对象包括目录和 inode。因此,页面缓存处理来自文件的数据,而 dentries 缓存管理文件系统对象。还有,内核使用一种最近最少使用 LRU 的算法来管理页面和 dentries 缓存。换句话说,当缓存已满并且要添加更多数据时,内核会删除最近使用最少的数据,以便为新数据腾出空间。
要优化缓存,我们可以修改几个参数:
vm.vfs_cache_pressure
vm.swappiness
vm.dirty_background_ratio
vm.dirty_background_bytes
vm.dirty_ratio
vm.dirty_bytes
vm.dirty_writeback_centisecs
vm.dirty_expire_centisecs
这些参数控制了系统总内存中可用于缓存的百分比。它们在内核将脏页写入存储之前调节缓存内存。重要的是,脏页是尚未写入辅助存储的内存页。通常,我们可以使用 sysctl 命令来配置 Linux 中的文件系统缓存。此外,sysctl 命令也可以修改 /etc/sysctl.conf 文件中的内核参数。这个文件包含了可以在运行时设置的系统范围的内核参数。
vm.vfs_cache_pressure
系统参数 vm.vfs_cache_pressure 控制内核回收用于缓存目录和 inode 对象的内存的趋势。
# sysctl -w vm.vfs_cache_pressure=50
vm.vfs_cache_pressure = 50
在这里,我们通过 sysctl 的 -w 选项将 vfs_cache_pressure 值设置为 50。因此,内核将优先满足 inode 和 dentry 缓存,而不是页面缓存。这有助于提升具有大量文件的系统的性能。值得注意的是,较高的值使内核更喜欢回收 inode 和 dentry,而不是缓存内存。另一方面,较低的值使其会去回收页面缓存的内存,而不是 inode 和 dentry 缓存。因此,我们可以根据自己的需要调整该值。
vm.swappiness
vm.swappiness 控制内核交换内存页的积极程度。降低该值意味着内核不太可能换掉不太常用的内存页。内核将这些页面缓存在内存中,以便更快的访问。可以使用 sysctl 命令来设置 vm.swappiness 参数的值。
# sysctl -w vm.swappiness=10
vm.swappiness = 10
该命令将 vm.swappiness 的值设置为 10。同样较低的值将使内核更愿意在内存中保留更多数据。因此,值越高内核会做越多的交换。
vm.dirty_background_ratio
vm.dirty_background_ratio 参数是系统内存量的百分比,表示在将脏页写入存储驱动器之前,可以填充多少的脏页。
假设我们将 64GB 内存系统的 vm.dirty_background_ratio 参数值设置为 10,则意味着 6.4GB 的数据脏页在写入存储之前可以保留在内存中。可以使用 sysctl 命令来设置 vm.dirty_background_ratio 参数的值。
# sysctl -w vm.dirty_background_ratio=10
vm.dirty_background_ratio = 10
我们也可以设置 vm.dirty_background_bytes 参数,来代替 vm.dirty_background_ratio。*_bytes 版本的参数采用以字节为单位的内存量。例如,我们可以将后台脏页缓存的内存量设置为 512MB
# sysctl -w vm.dirty_background_bytes=511870912
但是,如果我们设置了 * _bytes 参数,则 *_ratio 参数值将变为 0,反之亦然。
vm.dirty_ratio
vm.dirty_ratio 是系统内存的最大使用量的百分比,在将脏页写入存储驱动器之前,可以填充多少内存。在达到该使用量后,所有新的 I/O 活动都将停止,直到将脏页写入存储。值得注意的是,当我们为 vm.dirty_ratio 设置一个百分比的值时,vm.dirty_bytes 会变为 0,反之亦然。
# sysctl -w vm.dirty_ratio=20
vm.dirty_ratio = 20
如果我们为 vm.dirty _bytes 配置一个以字节为单位的值,则 vm.dirty_ratio 将变为 0。
dirty_expire_centisecs 和 dirty_writeback_centisecs
在断电的情况下,缓存在系统内存中的数据有丢失的风险。因此为了保护系统免于丢失数据,以下变量决定了将数据写入辅助存储的时间和频率:
vm.dirty_expire_centisecs
vm.dirty_writeback_centisecs
vm.dirty_expire_centisecs 控制数据在写入存储驱动器之前在缓存中可以保留多长时间。让我们来设置下该参数,以便数据可以在缓存中保留 40 秒。
# sysctl -w vm.dirty_expire_centisecs=4000
vm.dirty_expire_centisecs = 4000
在该情况下,缓存的信息在写入存储驱动器之前最多可以保留 40 秒。值得注意的是,1s 等于 100 centisecs。此外 vm.dirty_writeback_centisecs 参数,可用于控制后台写进程检查是否有要写入辅助存储的数据的频率。因此该值越低,频率越高,反之亦然。将 vm.dirty_writeback_centisecs 配置为每 5 秒检查一次缓存。
# sysctl -w vm.dirty_writeback_centisecs=500
vm.dirty_writeback_centisecs = 500