相较于Oracle,pg对操作系统的依赖要高很多,因此对于pg的调优很大一部分都在操作系统层面。最近刚好有看到别人聊关于numa这个话题,那么我们就一起来看看pg中numa该如何使用吧。
很多有经验的DBA对于numa的建议都是直接关掉,Oracle中更是建议如此,似乎这已经成为大家一种约定俗成的习惯了。对于大部分情况来说的确如此,但是我们还是得弄清楚为啥这么做,
当然你也可以说我不管什么系统我就无脑统统关掉numa,那我就只能
什么是NUMA?
在单CPU时代,CPU与内存的交互大致如下:
随着多CPU的出现,大家渐渐发现,如果还是像之前一样,所有的CPU都通过一个BUS(北桥)去连接RAM,那么必然会产生性能的瓶颈,于是NUMA架构便诞生了。通过将一个CPU和其临近的RAM当做一个 node,CPU 会优先访问距离近的 RAM。同时,CPU 直接有一个快速通道连接,所以 每个CPU 还是访问到所有的 RAM 位置(只是速度会有差异)。
为什么要关掉NUMA?
对于NUMA架构而言,每个CPU访问其对应的RAM时速度是很快的,但是如果需要访问其它node的RAM,那么就需要通过inter-connect通道访问,速度自然会有降低。但是你可能会纳闷就算这个速度再慢那也比直接从磁盘去访问快吧?
事实的确如此,因为NUMA的主要危害并不在此。真正让大家选择弃用NUMA的原因是常常会出现一个CPU NODE很忙,而其它的CPU NODE都十分空闲。因为在NUMA架构中,默认的内存分配方案就是:优先尝试在请求线程当前所处的CPU的Local内存上分配空间。如果local内存不足,优先淘汰local内存中无用的Page。
NUMA的好处
既然NUMA的问题这么多,那么为什么还会出现呢?
其实NUMA本身并没有问题,甚至这是多CPU发展的必然趋势,而真正导致出问题的是因为操作系统内存访问不均匀。
下面是关于NUMA性能的一张测试图
可以看到几乎所有情况下Interleave模式下的程序性能都要比默认的亲和模式要高,有时甚至能高达30%。究其根本原因是Linux服务器的大多数workload分布都是随机的:即每个线程在处理各个外部请求对应的逻辑时,所需要访问的内存是在物理上随机分布的。而Interleave模式就恰恰是针对这种特性将内存page随机打散到各个CPU Core上,使得每个CPU的负载和Remote Access的出现频率都均匀分布。相较NUMA默认的内存分配模式,死板的把内存都优先分配在线程所在Core上的做法,显然普遍适用性要强很多。
那么对于Oracle、pg这类数据库应用为什么都要关掉呢?就其原因还是因为数据库这种大规模内存使用的应用场景,并且外部的连接大多是随机的,这往往会导致出现大量的Remote Access,当我们是用NUMA避免了BUS的性能瓶颈,而Remote Access又成了新的瓶颈,有点拆了东墙补西墙的感觉。
PostgreSQL使用NUMA的建议
一般情况下就是直接关闭掉,在操作系统启动时使用numa off参数。那如果你发现已经启用了numa,例如:
那么我们也可以调整操作系统的参数去修改:
vm.zone_reclaim_mode = 0
kernel.numa_balancing=0
numactl --interleave=all pg_ctl start -D $PGDATA
- vm.zone_reclaim_mode:当一个内存区域(zone)内部的内存耗尽时,是从其内部进行内存回收还是可以从其他zone进行回收的选项,0表示可以从下一个zone找可用内存;
- kernel.numa_balancing:是否启用NUMA平衡功能,将任务移动到最近的内存或移动内存到任务执行最近的地方,0表上关闭;
- numactl --interleave=all:无视 NUMA 关于 CPU 内存分配的策略,可以使得各个 CPU 区域的内存均匀分配。
除此之外,如果你的一台数据库服务器上运行了多个PG数据库实例,那么让每个PG数据库实例使用不同的CPUSET也是一个比较好的方法。
总结
总的来说PG中受到NUMA的影响并没有那么大,如果你的数据库比较大,负载比较高可能得重点关注下这个问题,大部分情况下即使你没有关闭NUMA,按照前面的建议调整下相关参数即可。