PostgreSQL 教程: 优化 Linux 页面缓存

五月 7, 2024

摘要:在本教程中,您将学习如何优化 Linux 中的页面缓存。

目录

介绍

页面缓存是一种磁盘缓存,用于保存文件和可执行程序的数据,例如存有文件或块设备实际内容的页面。页面缓存(磁盘缓存)用于减少磁盘读取次数。

Linux 中的文件系统缓存是一种机制,它允许内核将经常访问的数据存储在内存中,以便更快地访问。内核使用页面缓存来存储最近从文件读取的数据,和文件系统的元数据。

例如,当一个程序从一个文件中读取数据时,内核会执行以下几项任务:

  1. 检查页面缓存以查看数据是否已在内存中。
  2. 如果数据在内存中,内核只是从缓存中返回数据。
  3. 否则,它会从存储驱动器读取数据,并将其副本存储在缓存中以供将来使用。

此外,内核还使用 dentries 缓存来存储有关文件系统对象的信息。这些文件系统对象包括目录和 inode。

因此,页面缓存处理来自文件的数据,而 dentries 缓存管理文件系统对象。

还有,内核使用一种最近最少使用(LRU)的算法来管理页面和 dentries 缓存。换句话说,当缓存已满并且要添加更多数据时,内核会删除最近使用最少的数据,以便为新数据腾出空间。

检查缓存

vmstat命令提供了有关虚拟内存使用情况的信息。特别是,它可以显示出用于缓存的内存使用量:

$ vmstat
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  6130448 11032 589532    0       0      422    52     160   362    3  3 76 18  0

cache 列显示了用于文件系统缓存的内存量(以 KB 为单位)。此外,要使用vmstat命令获得更详细的信息,我们可以使用 -s 选项:

$ vmstat -s
8016140 K total memory
1282340 K used memory
 207744 K active memory
 711356 K inactive memory
6133536 K free memory
  11032 K buffer memory
 589232 K swap cache
2097148 K total swap
      0 K used swap
2097148 K free swap
   3458 non-nice user cpu ticks
    389 nice user cpu ticks
   3371 system cpu ticks
  60823 idle cpu ticks
  20782 IO-wait cpu ticks
      0 IRQ cpu ticks
     34 softirq cpu ticks
      0 stolen cpu ticks
 494275 pages paged in
  56168 pages paged out
      0 pages swapped in
      0 pages swapped out
 170063 interrupts
 384058 CPU context switches
1673971944 boot time
   5151 forks

或者,我们也可以使用free命令,来检查系统中文件系统缓存的使用量。它在 buff/cache 列显示了内存使用情况(以 KB 为单位):

$ free
                  total        used           free      shared      buff/cache      available
Mem:            8016140     1284652        6130952      144680          600536       6353032
Swap:           2097148           0        2097148

-m 选项可将命令输出值更改成以 MB 为单位。值得注意的是,buff/cache 列的值是vmstat命令输出的 MemSwap 行的值之和。

页面缓存的设置

要优化页面缓存,我们可以修改几个参数:

  • 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 对象的内存的趋势:

$ sudo 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 参数:

$ sudo 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 的数据(脏页)在写入存储之前可以保留在内存中。

现在,让我们为系统配置 vm.dirty_background_ratio 参数的值:

$ sudo sysctl -w vm.dirty_background_ratio=10
vm.dirty_background_ratio = 10

或者,我们也可以设置 vm.dirty_background_bytes 参数,来代替 vm.dirty_background_ratio*_bytes 版本的参数采用以字节为单位的内存量。例如,我们可以将后台脏页缓存的内存量设置为 512MB:

$ sudo 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,反之亦然。为了说明这一点,让我们来定义 vm.dirty_ratio 的值:

$ sudo 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 秒:

$ sudo 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 秒检查一次缓存:

$ sudo sysctl -w vm.dirty_writeback_centisecs=500
vm.dirty_writeback_centisecs = 500

同样,500 centisecs 等于 5 秒。