选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.0 已于 2015 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

17.4. 管理内核资源 #

一个大型PostgreSQL安装会很快耗尽各种操作系统资源限制。(在某些系统上,出厂默认值非常低,你甚至不需要真正大型的安装就会遇到问题。)如果你遇到过这类问题,请继续阅读。

17.4.1. 共享内存和信号量 #

共享内存和信号量统称为System VIPC(连同消息队列,但消息队列与PostgreSQL无关)。几乎所有现代操作系统都提供这些特性,但其中许多系统默认没有启用它们或尺寸不足,尤其是随着可用内存和数据库应用需求的增长。(在Windows上,PostgreSQL为这些设施提供了自己的替代实现,因此可以忽略本节的大部分内容。)

完全缺少这些功能时,通常会在服务器启动时出现 Illegal system call 错误。在这种情况下,除了重新配置内核别无选择。没有它们,PostgreSQL 就无法工作。不过,在现代操作系统中,这种情况很少见。

PostgreSQL超出各种硬性IPC限制之一时,服务器会拒绝启动,并应留下带有指导性的错误消息,说明问题所在以及应如何处理(另见第 17.3.1 节)。相关内核参数在不同系统上的命名基本一致,表 17.1给出了概览;不过,设置它们的方法却各不相同。下面给出一些平台上的建议。

表 17.1. System V IPC参数

名称 描述 合理的值
SHMMAX 共享内存段的最大尺寸(字节) 至少数 MB(见正文)
SHMMIN 共享内存段的最小尺寸(字节) 1
SHMALL 可用共享内存的总量(字节或页面) 如果是字节,同SHMMAX;如果是页面,为ceil(SHMMAX/PAGE_SIZE)
SHMSEG 每个进程的最大共享内存段数目 只需要 1 段,但是默认值高很多
SHMMNI 系统范围内的最大共享内存段数目 SHMSEG外加其他应用的空间
SEMMNI 信号量标识符(即,集合)的最大数目 至少 ceil((max_connections + autovacuum_max_workers + 4) / 16)
SEMMNS 系统范围内的最大信号量数目 ceil((max_connections + autovacuum_max_workers + 4) / 16) * 17,并为其他应用保留空间
SEMMSL 每个集合中信号量的最大数目 至少 17
SEMMAP 信号量映射中的项数 见文本
SEMVMX 信号量的最大值 至少 1000 (默认值常常是 32767,如非必要不要更改)

最重要的共享内存参数是SHMMAX,即以字节计的共享内存段的最大尺寸。如果shmget返回像Invalid argument这样的错误消息,很可能是超出了这个限制。所需共享内存段的尺寸取决于若干PostgreSQL配置参数,如表 17.2所示。(你可能得到的任何错误消息都会包含失败分配请求的确切尺寸。) 作为临时解决办法,你可以调低其中某些设置来避免失败。虽然SHMMAX小到 2 MB 也能让PostgreSQL运行,但要获得可接受的性能,需要的远不止这个数。比较理想的设置是几百兆字节到几吉字节。

一些系统还对系统内共享内存的总量有限制(SHMALL)。请确保它对PostgreSQL以及使用共享内存段的任何其他应用来说都足够大。注意,在许多系统上SHMALL以页而不是字节计。

不太可能出问题的是共享内存段的最小尺寸(SHMMIN),对PostgreSQL来说应该最多大约是 500 kB(通常只是 1)。而系统范围(SHMMNI)或每个进程(SHMSEG)的最大共享内存段数目不太可能会导致问题,除非你的系统把它们设成零。

PostgreSQL为每个允许的连接(max_connections)和每个允许的自动清理工作进程(autovacuum_max_workers)各使用一个信号量,每 16 个组成一组。每组还包含第 17 个信号量,其中存放一个魔数,用来检测与其他应用程序使用的信号量集的冲突。系统中的信号量最大数量由SEMMNS设置,因此它必须至少等于max_connections加上autovacuum_max_workers,再加上每 16 个允许连接加工作进程一个的额外信号量(见表 17.1中的公式)。参数SEMMNI决定系统中同时可以存在的信号量集的数量上限,因此它必须至少为ceil((max_connections + autovacuum_max_workers + 4) / 16)。降低允许的连接数是失败时的一种临时变通办法,这种失败通常表现为semget函数返回措辞令人困惑的No space left on device

在某些情况下,可能还需要增大SEMMAP,使其至少与SEMMNS处于同一数量级。这个参数定义信号量资源映射的大小,映射中每个连续的可用信号量块都需要占用一项。每当一个信号量集合被释放时,它要么会并入与该释放块相邻的现有项,要么会登记为一个新的映射项。如果映射已满,被释放的信号量就会丢失(直到重启)。因此,随着时间推移,信号量空间碎片化可能会导致可用信号量少于应有数量。

SEMMSL 参数决定一个信号量集中可以包含多少个信号量,对于PostgreSQL,它必须至少为 17。

信号量撤销有关的其他各种设置,如SEMMNUSEMUME,不会影响PostgreSQL

AIX

至少从 5.1 版起,应该不需要对 SHMMAX 等参数进行任何特殊配置,因为它似乎已配置为允许将全部内存用作共享内存。这也是 DB/2 等其他数据库常用的配置。

不过,可能需要修改 /etc/security/limits 中的全局 ulimit 信息,因为文件大小(fsize)和文件数量(nofiles)的默认硬限制可能过低。

BSD/OS

共享内存.  默认只支持 4 MB 共享内存。请记住,共享内存是不可换页的,它被锁定在 RAM 中。要增加系统支持的共享内存量,可以在内核配置文件中加入类似下面的内容:

options "SHMALL=8192"
options "SHMMAX=\(SHMALL*PAGE_SIZE\)"

SHMALL以 4 kB 页计,因此值 1024 表示 4 MB 共享内存。所以上面的设置把最大共享内存区域增加到 32 MB。 对于运行 4.3 或更高版本的用户,可能还需要把KERNEL_VIRTUAL_MB增加到默认值248之上。 所有修改完成后,重新编译内核并重启。

Semaphores.  你可能还想同时增加信号量的数量;系统默认总数 60 只允许大约 50 个PostgreSQL连接。请在内核配置文件中设置你想要的值,例如:

options "SEMMNI=40"
options "SEMMNS=240"
FreeBSD

默认设置只适合小型安装(例如,默认的SHMMAX为 32 MB)。可以通过sysctlloader接口进行修改。以下参数可以用sysctl设置:

# sysctl kern.ipc.shmall=32768
# sysctl kern.ipc.shmmax=134217728

要让这些设置在重启后保持,请修改/etc/sysctl.conf

sysctl而言,这些信号量相关的设置是只读的,但可以在/boot/loader.conf中设置:

kern.ipc.semmni=256
kern.ipc.semmns=512
kern.ipc.semmnu=256

修改这些值后,需要重启才能使新设置生效。(注意:FreeBSD 不使用SEMMAP。较旧的版本会接受但忽略kern.ipc.semmap设置;较新的版本则直接拒绝它。)

你可能还希望配置内核,把共享内存锁定在 RAM 中,防止其被换出到交换区。这可以通过 sysctl 设置 kern.ipc.shm_use_phys 来实现。

如果通过启用 sysctlsecurity.jail.sysvipc_allowed 在 FreeBSD jail 中运行,应让不同 jail 中的 postmaster 使用不同的操作系统用户。这能提高安全性,因为它可以防止非 root 用户干扰不同 jail 中的共享内存或信号量,也能让 PostgreSQL 的 IPC 清理代码正常工作。(在 FreeBSD 6.0 及更高版本中,IPC 清理代码无法正确检测其他 jail 中的进程,导致无法在不同 jail 中使用同一端口运行 postmaster。)

FreeBSD 4.0 之前的版本行为类似于 OpenBSD (see below).

NetBSD

NetBSD 5.0 及更高版本中,可以用sysctl调整 IPC 参数,例如:

$ sysctl -w kern.ipc.shmmax=16777216

要让这些设置在重启后保持,请修改/etc/sysctl.conf

你可能还希望配置内核,把共享内存锁定在 RAM 中,防止其被换出到交换区。这可以通过 sysctl 设置 kern.ipc.shm_use_phys 来实现。

NetBSD 5.0 之前的版本行为与OpenBSD类似(见下文),只是参数应该用关键字options而不是option设置。

OpenBSD

编译内核时需要启用选项SYSVSHMSYSVSEM(默认已启用)。共享内存的最大尺寸由选项SHMMAXPGS(以页计)决定。下面展示了一个如何设置各参数的例子:

option        SYSVSHM
option        SHMMAXPGS=4096
option        SHMSEG=256

option        SYSVSEM
option        SEMMNI=256
option        SEMMNS=512
option        SEMMNU=256
option        SEMMAP=256

你可能还希望配置内核,把共享内存锁定在 RAM 中,防止其被换出到交换区。这可以通过 sysctl 设置 kern.ipc.shm_use_phys 来实现。

HP-UX

默认设置通常足以满足普通安装的需求。在 HP-UX 10 上,SEMMNS 的出厂默认值为 128,对较大的数据库站点来说可能过低。

可以在 System Administration ManagerSAM)的 Kernel ConfigurationConfigurable Parameters 中设置 IPC 参数。完成后选择 Create A New Kernel

Linux

默认的最大段尺寸是 32 MB,只对非常小的PostgreSQL安装够用。默认的最大总量是 2097152 页。除了使用巨页的不常见内核配置外,一页几乎总是 4096 字节(可以用getconf PAGE_SIZE验证)。这使得默认限制为 8 GB,通常够用,但并非总是如此。

可以通过以下接口更改共享内存大小设置:sysctl。例如,要允许 16 GB:

$ sysctl -w kernel.shmmax=17179869184
$ sysctl -w kernel.shmall=4194304

此外,可以将这些设置保存在以下文件中,使其在重启后仍然生效:/etc/sysctl.conf。强烈建议这样做。

很旧的发行版可能没有 sysctl 程序,但可以通过操作 /proc 文件系统进行等效更改:

$ echo 17179869184 >/proc/sys/kernel/shmmax
$ echo 4194304 >/proc/sys/kernel/shmall

其他默认值都相当充裕,通常不需要更改。

MacOS X

在 OS X 中配置共享内存的推荐方法是创建一个名为/etc/sysctl.conf的文件,其中包含这样的变量赋值:

kern.sysv.shmmax=4194304
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.sysv.shmall=1024

注意,在某些 OS X 版本中,全部五个共享内存参数都必须在/etc/sysctl.conf中设置,否则这些值会被忽略。

请注意,近期 OS X 版本会忽略将 SHMMAX 设为非 4096 整数倍的值的尝试。

在这个平台上,SHMALL 以 4 kB 的页为单位。

在较旧的 OS X 版本中,必须重启才能使共享内存参数的变更生效。从 10.5 起,除了 SHMMNI,都可以使用 sysctl 在线更改。但最好仍通过 /etc/sysctl.conf 设置所需的值,以便重启后保留这些值。

文件 /etc/sysctl.conf 只在 OS X 10.3.9 及更高版本中生效。如果运行的是更早的 10.3.x 版本,必须编辑文件 /etc/rc 并更改以下命令中的值:

sysctl -w kern.sysv.shmmax
sysctl -w kern.sysv.shmmin
sysctl -w kern.sysv.shmmni
sysctl -w kern.sysv.shmseg
sysctl -w kern.sysv.shmall

注意,/etc/rc 通常会被 OS X 系统更新覆盖,因此每次更新后可能都需要重新进行这些编辑。

在 OS X 10.2 及更早版本中,请改为编辑 /System/Library/StartupItems/SystemTuning/SystemTuning 文件中的这些命令。

SCO OpenServer

在默认配置中,每个共享内存段只允许 512 kB。要提高此设置,首先切换到目录/etc/conf/cf.d。要显示SHMMAX的当前值,运行:

./configure -y SHMMAX

要为SHMMAX设置新值,运行:

./configure SHMMAX=value

其中value是你要使用的新值(以字节为单位)。设置SHMMAX后,重新构建内核:

./link_unix

然后重启。

Solaris

至少在 2.6 版本中,共享内存段的默认最大尺寸对PostgreSQL来说太低。相关设置可以在/etc/system中修改,例如:

set shmsys:shminfo_shmmax=0x2000000
set semsys:seminfo_semmns=1024

要让更改生效,需要重启。

另见http://sunsite.uakom.sk/sunworldonline/swol-09-1997/swol-09-insidesolaris.html,其中介绍了Solaris下的共享内存。

UnixWare

UnixWare 7 中,默认配置下共享内存段的最大尺寸只有 512 kB。要显示SHMMAX的当前值,请运行:

/etc/conf/bin/idtune -g SHMMAX

这会显示当前值、默认值、最小值和最大值。要为SHMMAX设置新值,请运行:

/etc/conf/bin/idtune SHMMAX value

其中value是你要使用的新值(以字节计)。设置SHMMAX之后,重新构建内核:

/etc/conf/bin/idbuild -B

and reboot.

表 17.2. PostgreSQL shared memory usage

Usage 大致所需的共享内存字节数(按 8.3 计)
连接 (1800 + 270 * max_locks_per_transaction) * max_connections
自动清理工作进程 (1800 + 270 * max_locks_per_transaction) * autovacuum_max_workers
预备事务 (770 + 270 * max_locks_per_transaction) * max_prepared_transactions
共享磁盘缓冲区 (block_size + 208) * shared_buffers
WAL 缓冲区 (wal_block_size + 8) * wal_buffers
固定空间需求 770 kB

17.4.2. Resource Limits

类 Unix 操作系统会施加多种资源限制,这些限制可能干扰 PostgreSQL 服务器的运行。其中尤其重要的是:每个用户可用的进程数限制、每个进程可打开文件数限制,以及每个进程可用内存量限制。每一种限制都有限制和限制。实际生效的是软限制,但用户可以自行把它调高到不超过硬限制;硬限制则只能由 root 用户修改。系统调用setrlimit负责设置这些参数。shell 的内置命令ulimit(Bourne shell)或limitcsh)可用于在命令行控制资源限制。在 BSD 派生系统上,/etc/login.conf文件控制登录时设置的各种资源限制。详细信息请参阅操作系统文档。相关参数有maxprocopenfilesdatasize。例如:

default:\
...
        :datasize-cur=256M:\
        :maxproc-cur=256:\
        :openfiles-cur=256:\
...

-cur表示软限制;把它改为-max则表示设置硬限制。)

内核还可能对某些资源施加系统范围的限制。

  • Linux上,内核参数 /proc/sys/fs/file-max确定内核支持的最大打开文件数。 可以向该文件写入一个不同的数字来修改它,也可以在/etc/sysctl.conf中添加相应赋值。 每个进程的文件数上限是在内核编译时固定的;请参阅 /usr/src/linux/Documentation/proc.txt获取更多信息。

PostgreSQL服务器为每个连接使用一个进程,因此你至少应提供与允许连接数相同数量的进程,再加上系统其他部分所需的进程数。通常这不是问题,但如果你在一台机器上运行多个服务器,资源可能就会变得紧张。

打开文件数的出厂默认限制通常被设为对共享环境友好的值,也就是允许许多用户在一台机器上共存,而不会占用不成比例的系统资源。如果你在一台机器上运行很多服务器,这也许正合适;但在专用服务器上,你可能会希望提高这个限制。

另一方面,有些系统允许单个进程打开非常多的文件;如果不止少数几个进程都这么做,就很容易超过系统范围的限制。如果你遇到这种情况,又不想修改系统范围的限制,可以设置PostgreSQLmax_files_per_process配置参数来限制其打开文件的消耗。

17.4.3. Linux 内存过量分配 #

在 Linux 2.4 及更高版本中,默认的虚拟内存行为对 PostgreSQL 并非最佳。由于内核实现内存过量分配的方式,如果 PostgreSQL 或其他进程的内存需求导致系统耗尽虚拟内存,内核可能会终止 PostgreSQL 的 postmaster(主管服务器进程)。

如果发生这种情况,你会看到类似下面的内核消息(至于应到哪里查看此类消息,请参阅你的系统文档和配置):

Out of Memory: Killed process 12345 (postgres).

这表示 postgres 进程因内存压力而被终止。尽管现有数据库连接仍会继续正常运行,但新连接将不再被接受。要恢复服务,必须重启PostgreSQL

避免该问题的一种办法,是让PostgreSQL运行在一台你能确定不会被其他进程耗尽内存的机器上。如果内存紧张,增加操作系统交换空间也有助于避免这个问题,因为内存不足(OOM)杀手只有在物理内存和交换空间都耗尽时才会被触发。

如果导致系统耗尽内存的正是 PostgreSQL 自身,那么你可以通过调整配置来避免该问题。在某些情况下,调低与内存相关的配置参数会有帮助,尤其是 shared_bufferswork_mem。在其他情况下,允许数据库服务器接受过多连接也可能导致这一问题。很多时候,更好的做法可能是减小 max_connections,并转而使用外部连接池软件。

在 Linux 2.6 及更高版本中,可以修改内核的行为,使其不会过量分配内存。虽然此设置无法完全阻止 OOM 杀手 被调用,但会显著降低发生概率,从而使系统行为更健壮。方法是选择严格的过量分配模式,使用以下命令:sysctl

sysctl -w vm.overcommit_memory=2

或者在以下文件中加入等效条目:/etc/sysctl.conf。你可能还希望修改相关设置 vm.overcommit_ratio。详细信息参见内核文档文件 Documentation/vm/overcommit-accounting

另一种方法(无论是否修改vm.overcommit_memory都可以使用)是把 postmaster 进程的进程专属oom_adj值设置为-17,从而保证它不会被 OOM 杀手选中。最简单的做法是在 postmaster 的启动脚本中、调用 postmaster 之前执行

echo -17 > /proc/self/oom_adj

在 postmaster 的启动脚本中、调用 postmaster 之前执行上述命令。 注意这一操作必须以 root 身份进行,否则不会生效;因此由 root 拥有的启动脚本是最容易做到这一点的位置。如果你这样做了,可能还会希望在构建PostgreSQL时在CPPFLAGS中加入-DLINUX_OOM_ADJ=0。这会使 postmaster 的子进程以正常的oom_adj值零运行,这样 OOM 杀手在需要时仍能选中它们。

注意

据报告,某些厂商的 Linux 2.4 内核包含 2.6 版过量分配 sysctl 参数的早期实现。但是,在没有相关代码的 2.4 内核上将 vm.overcommit_memory 设为 2,会使情况更糟,而非更好。建议在 2.4 安装上尝试之前,检查实际内核源码(参见文件 mm/mmap.c 中的函数 vm_enough_memory),确认内核支持的功能。存在 overcommit-accounting 文档文件,不能作为该功能已存在的证据。如有任何疑问,请咨询内核专家或内核供应商。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。