PostgreSQL 教程: 检查后端进程的内存使用情况

六月 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” 问题的原因时,会非常有用。

了解更多

PostgreSQL 管理