在现代服务器普遍采用的NUMA(非统一内存访问)架构中,CPU访问其本地内存节点的速度远快于访问远端节点。对于像PostgreSQL这样严重依赖内存缓存性能的数据库系统,内存页在NUMA节点间的分布不均可能导致显著的性能瓶颈。因此,监控共享缓冲区的NUMA分布是进行高级性能优化的关键一步。
PostgreSQL社区在版本演进中持续增强了pg_buffercache扩展的功能,使其能够提供更细粒度的内存监控信息。本文将解析两个关键补丁,展示该功能从引入到完善的过程。
基础:引入NUMA感知视图 (ba2a3c2302)
首个重要补丁 ba2a3c2302f1248496322eba917b17a421499388 为pg_buffercache扩展(版本升至1.6)引入了NUMA架构的感知能力。
核心变更:
- 新增函数
pg_buffercache_numa_pages():这是一个C语言实现的集合返回函数。由于PostgreSQL数据库块(默认8KB)可能大于操作系统内存页(通常为4KB),一个缓冲区可能横跨多个OS页。该函数会返回每个缓冲区对应的每一个OS内存页及其所在的NUMA节点。
- 新增视图
pg_buffercache_numa:作为上述函数的便捷封装,方便用户直接查询。
关键细节与注意事项:
- 数据获取机制:为了获得准确的NUMA节点信息,函数需要主动“触摸”(访问)相关的内存页。首次在后台进程中查询此视图可能代价较高,因为它会触发对所有共享内存页的访问,甚至可能促使操作系统实际分配这些内存。
- 权限控制:视图和函数的执行权限仅授予
pg_monitor角色,对PUBLIC不可见。
- 局限性:该实现依赖于系统的
libnuma库。在不支持NUMA或未安装此库的系统上,查询将失败。
这个补丁为数据库管理员打开了一扇观察数据库内部内存与底层硬件架构如何交互的窗口,是进行NUMA调优的基础。
完善:兼容性与功能泛化 (4b203d499c)
为了解决上述依赖libnuma的局限性,补丁 4b203d499c610160e9867e6add2366780429344c 对功能进行了重构和扩展,并将模块版本升级至1.7。
核心改进:
- 重构内部函数:将
pg_buffercache_numa_pages()的逻辑重构为一个可选的内部C函数。
- 新增通用函数
pg_buffercache_os_pages(boolean):这是一个新的入口点。它接受一个布尔参数include_numa:
- 当参数为
true时,行为与原先的NUMA视图类似(如果系统支持)。
- 当参数为
false时,则仅返回缓冲区ID与OS页码的映射,完全绕过NUMA信息查询,从而在不支持NUMA的系统上也能正常工作,且效率更高。
- 新增视图
pg_buffercache_os_pages:此视图基于pg_buffercache_os_pages(false)创建,专为快速查看缓冲区到OS页的映射而设计,不包含NUMA信息。
- 重定义原有视图:
pg_buffercache_numa视图被重新定义为基于pg_buffercache_os_pages(true),保证了向后兼容性。
价值总结:
此补丁通过巧妙的代码抽象,解决了环境依赖问题,使得缓冲区-内存页映射的监控能力得以在所有PostgreSQL部署环境中使用。同时,它提供了更灵活的数据获取方式:用户既可以通过pg_buffercache_numa获取完整的NUMA拓扑信息,也可以通过轻量级的pg_buffercache_os_pages进行基础映射检查。
实践意义
对于运行在NUMA服务器上的高负载PostgreSQL实例,结合这两个补丁所提供的视图,管理员可以:
- 识别“远程内存访问”:发现哪些频繁访问的数据块恰好位于非本地NUMA节点,从而引发访问延迟。
- 验证配置效果:在调整了
numactl或PostgreSQL的NUMA相关参数后,直观验证共享缓冲区在节点间的分布是否更均衡。
- 进行容量规划:了解内存使用的物理分布,为硬件扩容或架构调整提供数据支持。
通过pg_buffercache扩展的持续增强,PostgreSQL为其用户提供了更强大的底层运维监控能力,助力构建更高性能、更稳定的数据库服务。
|