为了更好的运行PG数据库,操作系统的内存必须做好优化。与PG优化相关的操作系统内存优化主要涉及几个方面:内存规划、NUMA设置、HUGEPAGE设置、VM参数优化、SWAP相关优化等。本文所说的方法不仅仅可以用于PG数据库优化,大多数配置对于其他数据库的优化也有一定的参考价值。
要强调的一点是,对于绝大多数系统来说,过度的内存优化并不一定是必须的,只要保证足够的物理内存,就可以让PG数据库运行的十分好。对于会话数很多,并发访问量较大的数据库,注意设置HUGEPAGE,确保不要出现严重的换页,就可以保证数据库较为平稳高效的运行了。本文所谈到的大多数优化方案仅仅在部分极为特殊的高负载,高性能应用场景才是必须的。
内存规划
内存规划就是确定物理机或者虚拟机/云主机的内存大小。在小型机时代,我们总是使用CPU核数与内存比来做一个粗略的内存规划,目前这种规划方式也经常用于虚拟机/云主机的内存规划。实际上这种1:4/1:8的CPU核数与内存比的规划,在X86时代没有任何借鉴意义。目前的CPU核数都很高,每颗CPU的处理能力都比以前的CPU高了许多,比如说,以前一颗CPU核能够处理的IO量大约为200-300M/秒,而现在的一颗X86核心每秒处理的IO量差不多在1GB左右。我们如果还是按照传统的方式来规划内存是十分不合适的。物理内存的大小一定要与你的业务类型与会话数量相匹配,而不一定非要按照1:4/1:8这种僵化的方式去分配。在内存规划上,哪怕多分配50%内存,也不要按照刚刚好的方式去分配,除非你的预算十分紧张。对于PG数据库来说,足够的内存对于提高性能有巨大的帮助。
NMA设置
NUMA架构是大型SMP服务器为了解决内存IO性能问题而设计的一种架构,在NUMA架构下,所有的内存都会连接到某个CPU组上,其他CPU要访问这组内存都需要其他的CPU帮助读取和传输。CPU的核数越多,这种架构的内存访问的成本开销越大。不过大家可以放心的是,远程内存访问虽然性能低于本地内存,不过和物理IO相比,还是高出数个数量级。在绝大多数应用场景中,我们几乎可以忽略远程内存的访问延时问题,把整个物理内存当成一个独立的整体来看就可以了。。因此在绝大多数数据库系统中,我们可以使用十分简单的策略来对待NUMA问题。在服务器的BIOS上,我们可以通过启用 memory interleaving来确保服务器启用NUMA节点之间的内存互访。在LINUX系统启动的时候,我们需要使用numa off参数,确保LINUX启用时关闭NUMA。
对于大多数情况来说,我们可以在BIOS层面关闭NUMA支持,并且在OS启动参数中设置numa off参数,那么我们在OS上就可以不用关注NUMA问题了。如果在OS上没有关闭NUMA,也可以通过下面的手段让PG数据库在分配内存的时候不理会NUMA的远程内存。
vm.zone_reclaim_mode=0
vm.numa_balancing=0
numactl –interleave=all $PG启动命令
如果你在一个启用了NUMA的服务器上运行多个PG实例,那么你可以利用NUMA架构来获得最好的性能,这对于具有高性能计算要求的数据库应用中有一定的用途。通过设置多个CPU组,并把不同的PG实例分配到不同的CPU组上运行,可以获得最佳的运行效率。不过这种配置方法需要十分精细的管理手段,对于大多数客户的PG DBA来说,难度过大。在一般情况下,并不建议使用。
HUGEPAGE使用
普通的LINUX内存页是4K的,也就是说1M内存需要映射为256个页面。而linux中的HUGEPAGE每个页面是2M以上(不同的内核版本支持HUGEPAGE页面的大小不同,一般是2M-256M),比如:
上面例子中的HUGEPAGE就是2M大小。那么HUGEPAGE和普通内存页的使用有什么差异呢?当然一次性访问4K和一次性访问2M内存的性能是不存在太大的差异的,这是INTEL CPU的结构决定的。而最大的问题在于,使用不同的页大小,PAGETABLE的大小是不同的。因此,如果使用较小的页面,那么PAGETABLE会比较大。
当然如果操作系统中只有一份PAGETABLE,那么大不了也就多占用一些内存而已。不幸的是,在PG数据库中,PAGETABLE不会只有一份,每个需要使用shared buffer pool的进程都需要一个相同大小的PAGETABLE。这样问题就来了,如果我们系统中有几千个会话,那么PAGETABLE就十分巨大了。
我们做个简单的计算,比如,一个96G shared buffer pool的数据库,PAGETABLE的大小大约为144M,如果我们的系统中只有100个会话,那么大约占用14.4G的虚拟内存空间,如果有1000个会话,那么就会占用144G的虚拟内存,甚至比shared buffer pool还大。这种内存占用带来的系统换页、内存碎片化等等问题,在某些场景下就会变得十分严重。
因为共享内存的使用,同时使用共享内存的会话数量很大的情况下,一个不是特别大的物理内存区域的PAGETABLE的数量会随着会话数的增加而增加,从而导致PAGETABLE达到一个海量的大小。从上面的分析我们也可以得到一个结论,如果你的shared buffer pool比较大,同时会话数比较多,那么使用HUGEPAGE就一定会有很好的效果。否则HUGEPAGE带来的性能提升不会太明显。
较大的PAGETABLE不仅仅会占用过多的物理内存,也会让内存碎片化,同时访问较大的PAGETABLE还存在寻址开销增大的问题,因此对于使用较大shared buffer pool的PG数据库而言,如果会话数很多,那么不使用HUGEPAGE,回对数据库带来较大的性能下降,并可能在数据库启动一段时间之后因为内存碎片而出现内存访问引起的性能问题。其表现为系统负载并不高,CPU总的使用率也不高,但是各种系统调用都很慢,同时看到SYS CPU比例较高。
使用HUGEPAGE的时候,需要注意的是,操作系统配置HUGEPAGE后需要重启才能生效,而当我们PG数据库调整shared buffer pool的时候,要注意当前的HUGEPAGE是否够用,如果不够用就需要加大HUGEPAGE参数,并立即重启服务器。如果物理内存足够,我们也可以配置额外的HUGEPAGE容量以备今后shared buffer pool扩容。因为HUGEPAGE是无法被普通的会话使用的,因此如果你配置了HUGEPAGE暂不使用并不是一个好办法,既然配置了,就全部分配给shared buffer pool使用可能是一个更好的习惯。
LINUX为了解决HUGEPAGE配置的变化需要重启服务器的问题,推出了透明大页技术。透明大页不需要提前设置好,而是可用透明的动态使用。如果shared buffer pool需要100G的内存,2M的大页和4K的小页可以根据系统的内存情况动态的使用,这样就避免了HUGEPAGE动态管理不方便的问题。虽然透明大页可以解决普通大页管理的弊端,不过这种透明大页对于一些高负载的应用场景,可能带来内存严重碎片,影响操作系统内存分配性能的问题,目前还不太成熟。在某些环境中,数据库与操作系统的透明大页技术并未实现很好的融合,有可能使用透明大页带来一些负面的影响。因此在PG上暂时也不建议使用透明大页,并且在一些高负载的大型数据库系统中建议关闭操作系统的透明大页功能。
VM参数优化
虽然说对于一般的应用场景来说,LINUX VM参数不做调整,PG数据库也可以很好的运行,不过对于较为大型的PG数据库,VM参数依然是需要调整的。我们重点关注的VM参数包含两个方面,一个是VM内存与换页策略方面,另外一方面是操作系统文件缓冲脏数据回写的策略。这两方面的配置对于高并发,大负载的PG数据库性能优化十分重要。
内存与换页策略方面:
vm.swappiness=0
vm.min_free_kbytes设置足够大(根据不同的物理内存,设置几百兆到几个G)
vm.vfs_cache_press=200(保持缺省值)
文件缓冲脏块回写策略方面:
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
SWAP优化
作为一个数据库服务来说,不产生任何换页肯定是最好的,基于这种理想,有些DBA建议在PG数据库中,如果物理内存足够大,就关闭SWAP,从而提升整体性能。实际上来说对于一个长期运行的生产系统来说,关闭SWAP并不是一种特别好的模式,因为SWAP实际上是物理内存出现不足时,确保操作正常系统运行的十分有效的手段。比较好的管理模式时设置足够大的SWAP,而不是关闭SWAP。对于绝大多数系统来说,只要换页没有对我们的业务高峰产生明显的冲击,那么SWAP使用率在30%以下,并不会对PG数据库的稳定运行带来任何负面的影响。
作者:白鳝