六月 14, 2024
摘要:在本教程中,您将学习如何检查 PostgreSQL 中后端进程的内存使用情况,和进行故障处理。
目录
介绍
一个 postgres 后端进程,是从 postmaster 进程派生出的独立的操作系统进程。这实际上是 Linux 上的一个内存效率非常高的操作,因为很多页面可以在 postmaster 和新派生的 PostgreSQL 进程之间共享。但是,一旦后端进程开始执行代码本身来引导进程初始化,在我们的场景中对应 PostgreSQL 进程,它就会分配和改写自己的内存页,这些内存页对于进程是唯一的,并且保持分页状态,因此会添加到 RSS 中,从而不再共享。
PostgreSQL 处理的内存区域,由 PostgreSQL 管理,它使用自己的 palloc() 分配器,该分配器会调用 malloc(),但还提供了一些额外的服务,例如内存区域的管理。这是非常有用的,因为这可以方便对这些内存区域进行诊断。
GNU 调试器
PostgreSQL 的palloc
是一个分层的内存分配器,它包装了系统平台的分配器。用palloc
分配的内存会被分配给一个内存上下文,该上下文是以TopMemoryContext
为根节点的层次结构中的一部分。每个上下文都有一个名称。
您可以通过 gdb(GNU 调试器)调用MemoryContextStats(MemoryContext*)
函数,来转储一个内存上下文及其子项的统计信息。最常见的用法是:
$ gdb -p $backend_pid
(gdb) print MemoryContextStats(TopMemoryContext)
输出会写入到 stderr。这可能会出现在主服务器的日志文件中;或者是在 PostgreSQL 的日志收集器启动之前,由 init 系统使用的辅助日志服务,journald;或者,如果您是在没有 postmaster 的情况下,直接运行一个后端单进程的话,则会出现在屏幕上。
TopMemoryContext: 67424 total in 5 blocks; 12256 free (7 chunks); 55168 used
...
TopPortalContext: 8192 total in 1 blocks; 7664 free (0 chunks); 528 used
PortalContext: 1024 total in 1 blocks; 448 free (0 chunks); 576 used:
SPI Proc: 32768 total in 3 blocks; 11528 free (2 chunks); 21240 used
SPI TupTable: 8192 total in 1 blocks; 6544 free (0 chunks); 1648 used
PLpgSQL per-statement data: 8192 total in 1 blocks; 7936 free (0 chunks); 256 used
expanded array: 82299680 total in 5006 blocks; 32040 free (29 chunks); 82267640 used
...
Grand total: 83565536 bytes in 5233 blocks; 401536 free (148 chunks); 83164000 used
这里显示了 MemoryContextStats() 转储的开头部分,其中每个内存上下文都列出了自己的统计信息。
此外,尽管 PostgreSQL 会通过 palloc() 使用自己的内存分配逻辑,但最终还是调用的 malloc()。Malloc 有一些诊断方法,可以调用这些诊断方法来查看发生了什么。其中有些诊断方法,如函数malloc_stats()
和malloc_info()
。可以使用 gdb 附加到后端进程,在进程内调用该函数。
pg_log_backend_memory_contexts()
pg_log_backend_memory_contexts() 是一个系统函数,用于指示服务器对指定 PID 对应的后端进程,记录它的内存上下文。pg_log_backend_memory_contexts()
是在 PostgreSQL 14 中引入的。
pg_log_backend_memory_contexts()
的执行示例:
postgres=# SELECT pg_log_backend_memory_contexts(11727);
pg_log_backend_memory_contexts
--------------------------------
t
(1 row)
PostgreSQL 日志文件中的相关输出:
[2023-06-15 08:12:51 UTC] psql postgres postgres LOG: 00000: statement: SELECT pg_log_backend_memory_contexts(11727);
...
[2023-06-15 08:13:30 UTC] LOG: 00000: logging memory contexts of PID 11727
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 0; TopMemoryContext: 60528 total in 5 blocks; 16224 free (6 chunks); 44304 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; TopTransactionContext: 8192 total in 1 blocks; 6728 free (0 chunks); 1464 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; smgr relation table: 16384 total in 2 blocks; 4544 free (3 chunks); 11840 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; TransactionAbortContext: 32768 total in 1 blocks; 32504 free (0 chunks); 264 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; Portal hash: 8192 total in 1 blocks; 512 free (0 chunks); 7680 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; TopPortalContext: 8192 total in 1 blocks; 7928 free (0 chunks); 264 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; Relcache by OID: 16384 total in 2 blocks; 7616 free (3 chunks); 8768 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; CacheMemoryContext: 262144 total in 6 blocks; 128408 free (3 chunks); 133736 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; WAL record construction: 49776 total in 2 blocks; 6344 free (0 chunks); 43432 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; PrivateRefCount: 8192 total in 1 blocks; 2584 free (0 chunks); 5608 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; MdSmgr: 8192 total in 1 blocks; 7896 free (0 chunks); 296 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; LOCALLOCK hash: 8192 total in 1 blocks; 512 free (0 chunks); 7680 used
[2023-06-15 08:13:30 UTC] LOG: 00000: level: 1; ErrorContext: 8192 total in 1 blocks; 7928 free (4 chunks); 264 used
[2023-06-15 08:13:30 UTC] LOG: 00000: Grand total: 658848 bytes in 38 blocks; 270616 free (32 chunks); 388232 used
总结
本教程向我们介绍了如何在 PostgreSQL 中转储后端进程的内存使用信息。这在帮助我们快速定位一些 “Out of memory” 问题的原因时,会非常有用。