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

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.2 已于 2017 年 11 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

17.4. 管理内核资源 #

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

17.4.1. 共享内存和信号量 #

共享内存和信号量统称为System V IPC(连同消息队列,但消息队列与PostgreSQL无关)。几乎所有现代操作系统都提供这些特性,但其中许多系统默认没有开启它们或尺寸不足,尤其是随着可用 RAM 和数据库应用的需求增长。(在 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 + 5) / 16)
SEMMNS 系统范围内的最大信号量数目 ceil((max_connections + autovacuum_max_workers + 5) / 16) * 17,并为其他应用保留空间
SEMMSL 每个集合中信号量的最大数目 至少 17
SEMMAP 信号量映射中的项数 见文本
SEMVMX 信号量的最大值 至少 1000 (默认值常常是 32767,如非必要不要更改)

最重要的共享内存参数是 SHMMAX,即共享内存段的最大字节数。如果你从 shmget 得到类似Invalid argument的错误消息,很可能是超出了这个限制。所需共享内存段的大小取决于若干 PostgreSQL 配置参数,如表 17.2所示。(你可能得到的任何错误消息都会包含失败分配请求的确切大小。)作为一种临时解决方案,你可以降低其中某些设置来避免失败。虽然 SHMMAX 小到 2 MB 时也能让 PostgreSQL 运行,但要获得可接受的性能需要大得多的值。理想的设置在几百 MB 到几 GB 之间。

有些系统还对系统中的共享内存总量有限制(SHMALL)。请确保它足以容纳 PostgreSQL 以及其他使用共享内存段的应用程序。注意,在许多系统上,SHMALL 以页而非字节为单位。

不太可能出问题的是共享内存段的最小尺寸(SHMMIN),对PostgreSQL来说应该最多大约是 500 kB。而系统范围(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 + 5) / 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)的默认硬限制可能过低。

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。)

4.0 之前的 FreeBSD 版本与 OpenBSD 的行为相同(见下文)。

NetBSD

NetBSD 5.0 及更高版本中,可以通过以下命令调整 IPC 参数:sysctl。例如:

# sysctl -w kern.ipc.semmni=100

要让这些设置在重启后仍然生效,请修改 /etc/sysctl.conf

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

5.0 之前的 NetBSD 版本与 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

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

Mac OS X

在 Mac 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 至 2.9(Solaris 6 至 Solaris 9)

可以在以下文件中更改相关设置:/etc/system。例如:

set shmsys:shminfo_shmmax=0x2000000
set shmsys:shminfo_shmmin=1
set shmsys:shminfo_shmmni=256
set shmsys:shminfo_shmseg=256

set semsys:seminfo_semmap=256
set semsys:seminfo_semmni=512
set semsys:seminfo_semmns=512
set semsys:seminfo_semmsl=32

需要重启才能使变更生效。另请参见 http://sunsite.uakom.sk/sunworldonline/swol-09-1997/swol-09-insidesolaris.html,了解旧版 Solaris 中共享内存的信息。

Solaris 2.10(Solaris 10)及更高版本
OpenSolaris

在 Solaris 10 及更高版本和 OpenSolaris 中,默认共享内存和信号量设置足以满足大多数 PostgreSQL 应用的需求。Solaris 现在默认将 SHMMAX 设为系统 RAM 的四分之一。要进一步调整此设置,请使用与以下用户关联的项目设置:postgres。例如,执行以下命令时使用的用户为 root

projadd -c "PostgreSQL DB User" -K "project.max-shm-memory=(privileged,8GB,deny)" -U postgres -G postgres user.postgres

该命令会新增user.postgres项目,并把postgres用户的共享内存上限设为 8GB;它会在该用户下次登录时或重启PostgreSQL时(不是重新加载)生效。上述示例假定PostgreSQLpostgres组中的postgres用户运行。不需要重启操作系统。

对于会承载大量连接的数据库服务器,我们还建议修改以下内核设置:

project.max-shm-ids=(priv,32768,deny)
project.max-sem-ids=(priv,4096,deny)
project.max-msg-ids=(priv,4096,deny)

此外,如果你正在某个区(zone)中运行PostgreSQL,可能也需要提高该区的资源使用限制。关于projectsprctl的更多信息,请参见System Administrator's Guide中的 "Chapter 2: Projects and Tasks"。

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

然后重启。

表 17.2. PostgreSQL 共享内存用量

用途 所需共享内存字节数的近似值(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. 资源限制

类 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 并非最佳。由于内核实现内存overcommit(过量分配)的方式,如果 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_score_adj值设为 -1000, 从而保证它不会成为 OOM 杀手的目标。最简单的做法是在 postmaster 启动脚本中、调用 postmaster 之前执行:

echo -1000 > /proc/self/oom_score_adj

请注意,这个操作必须以 root 身份完成,否则不会生效;因此,由 root 拥有的启动脚本是最容易执行该操作的位置。 如果这样做,还可以在构建 PostgreSQL 时向 CPPFLAGS 添加 -DLINUX_OOM_SCORE_ADJ=0。这会使 postmaster 子进程以常规的 oom_score_adj值零运行,以便 OOM 杀手在需要时仍可将它们作为目标。

较旧的 Linux 内核不提供 /proc/self/oom_score_adj,但可能提供名为 /proc/self/oom_adj 的同类功能的早期版本。其工作方式相同,只是禁用值为 -17 而非 -1000PostgreSQL相应的构建标志是 -DLINUX_OOM_ADJ=0

注意

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

提交更正

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