尽量减少 PostgreSQL 中的缓存未命中?

Léo*_* 준영 5 postgresql performance cache configuration postgresql-9.4 postgresql-performance

您可以按照此处所述计算缓存未命中。
但是,我对如何最小化 PostgreSQL 9.4.3 在 x86_64-unknown-linux-gnu 上的现象很感兴趣,它由 gcc (Debian 4.9.2-10) 4.9.2, 64-bit 编译。我有一些基于哈希表的算法,它们通过随机访问导致很多缓存未命中。我对如何最大限度地减少 PostgreSQL 中的缓存未命中感兴趣。

如何通过设计最大限度地减少 PostgreSQL 中的缓存未命中?

Kas*_*dry 2

使用 PostgreSQL 缓存内容是在文件系统缓存中可以拥有的内容shared_buffers和文件系统缓存中拥有的内容之间取得平衡,并避免它们都被其他进程推出。

在 PostgreSQL 9.4 上您可以做的第一件事就是huge_pages=on在您的postgresql.conf.

这还涉及到进行一些操作系统更改,以允许 PostgreSQL 在启用此功能的情况下启动。适当的 sysctl 变量是vm.nr_hugepages

vm.nr_hugepages您可以使用以下 shell 脚本快速而粗略地计算您应该设置的内容。

echo $(grep ^VmPeak /proc/$(cat /var/run/postgresql/9.4-main.pid)/status | sed -e 's/VmPeak://' | sed -e 's/kB//' | sed -e 's/[ \t]//g')/$(grep Hugepagesize /proc/meminfo | sed -e 's/Hugepagesize://' | sed -e 's/kB//' | sed -e 's/[ \t]//g') | bc -l | awk '{print int($1+1)}'

此行从 中正在运行的 PostgreSQL 进程获取 VmPeak /proc/$pid/status,它告诉您 PostgreSQL 进程的峰值虚拟内存大小。该数字以 kB 为单位。它清理间距和额外的输出,然后获取Hugepagesizefrom的测量/proc/memstat值(在我的例子中为 2048 kB),然后进行适当的除法,将输出四舍五入到最接近的整数,然后添加 1 作为安全裕度。

就我而言,是 2147。

通过执行以下操作使其永久化:

echo "vm.nr_hugepages=2147" >>/etc/sysctl.d/postgresql.conf

这很重要,原因如下(摘自文档):

/proc/sys/vm/nr_hugepages 表示内核大页池中当前“持久”大页的数量。当任务释放时,“持久”大页将返回到大页池。具有 root 权限的用户可以通过增加或减少“nr_hugepages”的值来动态分配更多或释放一些持久大页面。

用作大页的页被保留在内核内部,不能用于其他目的。大页在内存压力下无法换出。

因此,postgres 进程为shared_buffers 抓取的页面在内存压力下不会被换出。而且您的处理器的 TLB 压力也会更小。

接下来,我们调整 OOMKiller,因为随机谋杀 postgres 进程的东西不是好公民。这些设置强烈鼓励它不要开火。

echo "vm.overcommit_memory=2" >>/etc/sysctl.d/postgresql.conf

echo "vm.overcommit_ratio=100" >>/etc/sysctl.d/postgresql.conf

接下来我们设置几个内核调度程序 sysctls:

echo "kernel.sched_autogroup_enabled=0" >>/etc/sysctl.d/postgresql.conf

echo "kernel.sched_migration_cost=5000000" >>/etc/sysctl.d/postgresql.conf

迁移成本是调度程序将迁移的进程视为“高速缓存热”并因此不太可能重新迁移的总时间。

启用自动分组基本上通过 setsid() 对任务进行分组,因此感知响应能力得到改善。但在服务器系统上,像 PostgreSQL 这样的大型守护进程将从同一个 setid() 启动,并有效地阻止 CPU 周期,以支持不太重要的任务。

之后,我们可以调整交换性,这是一个控制系统将进程交换出物理内存的程度的旋钮。数字越大,换出越积极,数字越小,文件系统缓存中的内容保留时间越长。将其设置为零会增加内存和 I/O 压力下 OOM 杀死的机会。

echo "vm.swappiness=10" >>/etc/sysctl.d/postgresql.conf

这些控制着脏数据从文件系统缓存同步回磁盘的频率。由于无法释放页面缓存中的脏对象,因此更积极地回写可以保持更多页面可供使用,并有助于避免大量磁盘 IO 突发。

echo "vm.dirty_ratio=2" >>/etc/sysctl.d/postgresql.conf

echo "vm.dirty_background_ratio=1" >>/etc/sysctl.d/postgresql.conf

由于您的 PostgreSQL 版本输出显示 GCC 4.9,我假设您正在运行 Debian Jessie 或衍生版本,因此 3.16 内核将避免 3.2 内核所存在的一些真正可怕的 I/O 问题,因此这无疑是个好消息。

调整完所有这些设置后,重新启动系统。这将有助于确保分配时大页不会碎片化。不过,最好、最可靠的方法是将hugepages=2147(我的服务器上需要的号码)放在/etc/default/grubGRUB_CMDLINE_LINUX,然后运行update-grub,然后重新启动。但我会测试一下这样做的必要性,因为它比 sysctl 更难更改。

这些应该为您提供文件系统缓存和shared_buffers. 之后,确保服务器上运行的进程数量最少(因为它们都竞争资源),应该可以最大限度地减少您正在寻找的页面缓存未命中。

有关大页及其影响的进一步阅读,请参阅hugetlbpage 文档

虚拟机设置及其效果位于虚拟机文档中。

这是对 Linux 内存系统理解和优化内存利用率的一种非常平易近人的处理

PostgreSQL 文档在内核资源页面底部详细介绍了大页面的影响

希望有帮助。=)