18.4. Management 内核资源

PostgreSQL 有时可能会耗尽各种 os 资源的限制,尤其是当服务器的多个副本在同一系统上或在非常大的安装中运行时。本节说明了 PostgreSQL 使用的内核资源以及解决与内核资源消耗有关的问题可采取的步骤。

18 .4.1. 共享内存和 signal 量

PostgreSQL 要求 os 提供进程间通信(IPC)功能,特别是共享内存和 signal 量。 Unix 派生的系统通常提供“系统 V” IPC,“ POSIX” IPC 或两者。 Windows 具有自己的这些功能的实现,此处不再讨论。

这些功能的完全缺乏通常通过服务器启动时出现“非法系统调用”错误来表明。在这种情况下,别无选择,只能重新配置内核。没有它们,PostgreSQL 将无法工作。但是,这种情况在现代 os 中很少见。

启动服务器后,PostgreSQL 通常会分配少量的 System V 共享内存,以及大量的 POSIX(mmap)共享内存。另外,在服务器启动时会创建大量的 signal 量,可以是 System V 或 POSIX 风格。当前,POSIXsignal 量用于 Linux 和 FreeBSD 系统,而其他平台则使用 System Vsignal 量。

Note

在 PostgreSQL 9.3 之前,仅使用 System V 共享内存,因此启动服务器所需的 System V 共享内存量要大得多。如果您正在运行服务器的旧版本,请查阅服务器版本的文档。

System V IPC 功能通常受系统范围分配限制的约束。当 PostgreSQL 超过这些限制之一时,服务器将拒绝启动,并应留下指示性错误消息,描述问题及其处理方法。 (另请参见Section 18.3.1。)相关内核参数在不同系统中的名称一致; Table 18.1概述。但是,设置它们的方法各不相同。以下是一些平台的建议。

表 18.1. 系统 V IPC 参数

NameDescription运行一个 PostgreSQL 实例所需的值
SHMMAX共享内存段的最大大小(字节)至少 1kB,但默认值通常更高
SHMMIN共享内存段的最小大小(字节)1
SHMALL可用共享内存总量(字节或页)SHMMAX(如果为字节)或ceil(SHMMAX/PAGE_SIZE)(为页)相同,再加上其他应用程序的空间
SHMSEG每个进程的最大共享内存段数只需要 1 个细分,但默认设置要高得多
SHMMNI全系统共享内存段的最大数量SHMSEG加上其他应用程序的空间
SEMMNIsignal 灯标识符的最大数量(即,集合)至少ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16)加其他应用程序的空间
SEMMNS全系统最大 signal 量ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) * 17加上其他应用程序的空间
SEMMSL每组最大 signal 量至少 17
SEMMAPsignal 量图中的条目数see text
SEMVMXsignal 量最大值至少 1000(默认值通常是 32767;除非有必要,否则请不要更改)

PostgreSQL 需要为服务器的每个副本提供几个字节的 System V 共享内存(在 64 位平台上通常为 48 个字节)。在大多数现代 os 上,可以轻松分配此数量。但是,如果您正在运行服务器的许多副本,或者其他应用程序也在使用 System V 共享内存,则可能有必要增加SHMALL,这是系统范围内 System V 共享内存的总量。请注意,在许多系统上,SHMALL是按页而不是字节进行度量的。

引起问题的可能性较小的是共享内存段的最小大小(SHMMIN),对于 PostgreSQL,最大大小应约为 32 个字节(通常仅为 1)。除非系统将其设置为零,否则系统范围(SHMMNI)或每个进程(SHMSEG)的最大段数不太可能引起问题。

使用 System Vsignal 量时,PostgreSQL 在每组 16 个 signal 集中使用每个允许的连接(max_connections),允许的 autovacuum worker 进程(autovacuum_max_workers)和允许的后台进程(max_worker_processes)一个 signal 量。每个这样的 signal 集还将包含第 17 个 signal 量,其中包含“魔术数”,以检测与其他应用程序使用的 signal 量集的冲突。系统中 signal 灯的最大数量由SEMMNS设置,因此必须至少与max_connectionsautovacuum_max_workersmax_worker_processes一样高,并且每 16 个允许的连接数加上一个额外的 Worker 数(请参阅Table 18.1中的公式)。参数SEMMNI确定一次可以在系统上存在的 signal 量集的数量限制。因此,此参数必须至少为ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16)。减少允许的连接数是解决故障的临时解决方法,这些故障通常会从函数semget措辞为“设备上无空间”。

在某些情况下,可能还需要将SEMMAP增加到至少SEMMNS的数量级。如果系统具有此参数(很多没有),则它将定义 signal 灯资源 Map 的大小,其中每个相邻的可用 signal 灯块都需要一个条目。释放 signal 集后,它将被添加到与释放的块相邻的现有条目中,或者将其注册在新的 Map 条目下。如果 Map 已满,则释放的 signal 量会丢失(直到重新启动)。随着时间的流逝,signal 量空间的碎片化可能导致可用 signal 量少于应有的数量。

与“signal 量撤消”相关的各种其他设置(例如SEMMNUSEMUME)不会影响 PostgreSQL。

使用 POSIXsignal 量时,所需的 signal 量与 System V 相同,即每个允许的连接(max_connections),允许的 autovacuum worker 进程(autovacuum_max_workers)和后台的进程(max_worker_processes)一个 signal 量。在首选此选项的平台上,对 POSIXsignal 量的数量没有特定的内核限制。

  • AIX

    • 至少从 5.1 版开始,不必对诸如SHMMAX之类的参数进行任何特殊配置,因为它似乎已配置为允许将所有内存用作共享内存。这种配置通常用于其他数据库,例如 DB/2.

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

  • FreeBSD

    • 可以使用sysctlloader界面更改默认 IPC 设置。可以使用sysctl设置以下参数:
# sysctl kern.ipc.shmall=32768
# sysctl kern.ipc.shmmax=134217728

要使这些设置在重新启动后仍然有效,请修改/etc/sysctl.conf

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

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

修改该文件后,需要重新启动才能使新设置生效。

您可能还希望将内核配置为将共享内存锁定到 RAM 中,并防止将其调出以进行交换。这可以使用sysctl设置kern.ipc.shm_use_phys完成。

如果通过启用 sysctl 的security.jail.sysvipc_allowed在 FreeBSD 监狱中运行,则在不同监狱中运行的邮局主管应由不同的 os 用户运行。这可以提高安全性,因为它可以防止非 root 用户干扰不同监狱中的共享内存或 signal 量,并允许 PostgreSQL IPC 清理代码正常运行。 (在 FreeBSD 6.0 及更高版本中,IPC 清理代码无法正确检测其他监狱中的进程,从而阻止了邮局主管在不同监狱中的同一端口上运行.)

FreeBSD 4.0 之前的版本像旧的 OpenBSD 一样工作(见下文)。

  • NetBSD

    • 在 NetBSD 5.0 和更高版本中,可以使用sysctl来调整 IPC 参数,例如:
# sysctl -w kern.ipc.semmni=100

要使这些设置在重新启动后仍然有效,请修改/etc/sysctl.conf

通常,您将需要增加kern.ipc.semmnikern.ipc.semmns,因为 NetBSD 的默认设置太小了。

您可能还希望将内核配置为将共享内存锁定到 RAM 中,并防止将其调出以进行交换。这可以使用sysctl设置kern.ipc.shm_use_phys完成。

NetBSD 5.0 之前的版本类似于旧的 OpenBSD(请参见下文),除了内核参数应使用关键字options而不是option设置。

  • OpenBSD

    • 在 OpenBSD 3.3 和更高版本中,可以使用sysctl来调整 IPC 参数,例如:
# sysctl kern.seminfo.semmni=100

要使这些设置在重新启动后仍然有效,请修改/etc/sysctl.conf

您通常会希望增加kern.seminfo.semmnikern.seminfo.semmns,因为 OpenBSD 的默认设置太小了。

在较旧的 OpenBSD 版本中,您将需要构建自定义内核来更改 IPC 参数。确保也启用了选项SYSVSHMSYSVSEM。 (默认情况下是它们.)下面显示了如何在内核配置文件中设置各种参数的示例:

option        SYSVSHM
option        SHMMAXPGS=4096
option        SHMSEG=256

option        SYSVSEM
option        SEMMNI=256
option        SEMMNS=512
option        SEMMNU=256
  • HP-UX

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

可以在系统 Management 器(SAM)中的“内核配置”→“可配置参数”下设置 IPC 参数。完成后,选择“创建新内核”。

  • Linux

    • 默认的最大段大小为 32 MB,默认的最大总大小为 2097152 页。一个页面几乎总是 4096 字节,除非在具有“巨大页面”的异常内核配置中使用(使用getconf PAGE_SIZE进行验证)。

共享内存大小设置可以通过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

    • 在 macOS 中配置共享内存的推荐方法是创建一个名为/etc/sysctl.conf的文件,其中包含变量分配,例如:
kern.sysv.shmmax=4194304
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.sysv.shmall=1024

请注意,在某些 macOS 版本中,必须在/etc/sysctl.conf中设置所有五个共享内存参数,否则这些值将被忽略。

请注意,最新发行的 macOS 会忽略将SHMMAX设置为不是 4096 的整数倍的值的尝试。

SHMALL在此平台上以 4 KB 页面计。

在较早的 macOS 版本中,您将需要重新启动才能使共享内存参数中的更改生效。从 10.5 开始,可以使用 sysctl 快速更改除SHMMNI以外的所有内容。但是,仍然最好通过/etc/sysctl.conf设置您的首选值,以便在重新启动后保留这些值。

仅在 macOS 10.3.9 及更高版本中支持文件/etc/sysctl.conf。如果运行的是 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通常会被 macOS 系统更新覆盖,因此您应该期望在每次更新后必须重做这些编辑。

在 macOS 10.2 和更早版本中,请在文件/System/Library/StartupItems/SystemTuning/SystemTuning中编辑这些命令。

  • 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

您需要重新启动才能使更改生效。有关旧版本 Solaris 下共享内存的信息,另请参见http://sunsite.uakom.sk/sunworldonline/swol-09-1997/swol-09-insidesolaris.html

  • Solaris 2.10(Solaris 10)和更高版本
    OpenSolaris

    • 在 Solaris 10 和更高版本以及 OpenSolaris 中,默认的共享内存和 signal 设置对于大多数 PostgreSQL 应用程序来说已经足够了。 Solaris 现在默认为系统 RAM 的四分之一的SHMMAX。要进一步调整此设置,请使用与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(不重新加载)时生效。以上假设 PostgreSQL 由postgres组中的postgres用户运行。无需重启服务器。

对于具有大量连接的数据库服务器,建议的其他其他内核设置更改包括:

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

此外,如果在区域内运行 PostgreSQL,则可能还需要提高区域资源使用限制。有关projectsprctl的更多信息,请参见《系统 Management 员指南》中的“第二章:项目和任务”。

18 .4.2. 系统删除 IPC

如果正在使用 systemd,则必须注意 os 不会过早删除 IPC 资源(共享内存和 signal 灯)。从源安装 PostgreSQL 时,这尤其值得关注。 PostgreSQL 分发包的用户受影响的可能性较小,因为通常将postgres用户创建为系统用户。

logind.conf中的RemoveIPC设置控制在用户完全注销时是否删除 IPC 对象。系统用户免税。在 stock systemd 中,此设置默认为 on,但某些 os 发行版将其默认为 off。

启用此设置后,通常观察到的效果是 PostgreSQL 服务器使用的 signal 对象在明显随机的时间被删除,从而导致服务器崩溃,并显示日志消息,例如

LOG: semctl(1234567890, 0, IPC_RMID, ...) failed: Invalid argument

systemd 对不同类型的 IPC 对象(共享内存与 signal 量,System V 与 POSIX)的处理略有不同,因此可能会观察到某些 IPC 资源没有以与其他资源相同的方式删除。但是,不建议依靠这些细微的差异。

当 Management 员以postgres用户或类似身份登录时,“用户注销”可能是维护工作的一部分,也可能是手动发生的,因此通常很难避免。

什么是“系统用户”是在 system 编译时根据/etc/login.defs中的SYS_UID_MAX设置确定的。

打包和部署脚本应谨慎使用useradd -radduser --system或等效名称将postgres用户创建为系统用户。

或者,如果用户帐户创建错误或无法更改,则建议设置

RemoveIPC=no

/etc/systemd/logind.conf或其他适当的配置文件中。

Caution

至少必须确保这两件事中的一项,否则 PostgreSQL 服务器将非常不可靠。

18 .4.3. 资源限制

类似于 Unix 的 os 强制执行各种资源限制,这些资源限制可能会干扰 PostgreSQL 服务器的操作。特别重要的是限制每个用户的进程数,每个进程的打开文件数以及每个进程可用的内存量。这些每个都有一个“硬”和“软”限制。软限制是实际要考虑的内容,但用户可以更改为硬限制。硬限制只能由 root 用户更改。系统调用setrlimit负责设置这些参数。 Shell 的内置命令ulimit(Bourne shell)或limit(csh)用于从命令行控制资源限制。在源自 BSD 的系统上,文件/etc/login.conf控制登录期间设置的各种资源限制。有关详细信息,请参见 os 文档。相关参数是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 服务器的每个连接使用一个进程,因此,除了系统其余部分所需的连接之外,您还应至少提供与允许的连接一样多的进程。通常这不是问题,但是如果您在一台计算机上运行多个服务器,则可能会变得很紧张。

打开文件的出厂默认限制通常设置为“社交友好”值,该值允许许多用户在计算机上共存,而不会使用不适当的系统资源。如果您在一台计算机上运行许多服务器,这也许就是您想要的,但是在专用服务器上,您可能希望提高此限制。

另一方面,某些系统允许单个进程打开大量文件。如果这样做的过程多于几个,则很容易超过系统范围的限制。如果发现这种情况,并且不想更改系统范围的限制,则可以设置 PostgreSQL 的max_files_per_process配置参数来限制打开文件的使用。

18 .4.4. Linux 内存过量使用

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

如果发生这种情况,您将看到一个看起来像这样的内核消息(有关该消息的查询位置,请咨询系统文档和配置):

Out of Memory: Killed process 12345 (postgres).

这表明postgres进程由于内存压力而终止。尽管现有的数据库连接将 continue 正常运行,但不会接受任何新连接。要恢复,PostgreSQL 将需要重新启动。

避免此问题的一种方法是在可以确保其他进程不会在内存不足的情况下运行机器的机器上运行 PostgreSQL。如果内存紧张,则增加 os 的交换空间可以帮助避免此问题,因为仅当物理内存和交换空间用完时才会调用内存不足(OOM)杀手。

如果 PostgreSQL 本身是导致系统内存不足的原因,则可以通过更改配置来避免此问题。在某些情况下,可能有助于降低与内存相关的配置参数,尤其是shared_bufferswork_mem。在其他情况下,此问题可能是由于允许与数据库服务器本身的连接过多而引起的。在许多情况下,最好减少max_connections,而是使用外部连接池软件。

在 Linux 2.6 和更高版本上,可以修改内核的行为,以便它不会“过量使用”内存。尽管此设置不会完全阻止OOM killer被调用,但是它将大大降低机会,因此将导致更强大的系统行为。这是通过sysctl选择严格的过量使用模式来完成的:

sysctl -w vm.overcommit_memory=2

或在/etc/sysctl.conf中放置一个等效条目。您可能还希望修改相关的设置vm.overcommit_ratio。有关详细信息,请参见内核文档文件https://www.kernel.org/doc/Documentation/vm/overcommit-accounting

可以使用或不更改vm.overcommit_memory的另一种方法是将邮局主管进程的特定于进程的* OOM 分数调整*值设置为-1000,从而确保 OOM 杀手不会将其作为目标。最简单的方法是执行

echo -1000 > /proc/self/oom_score_adj

在调用邮局局长之前,在邮局局长的启动脚本中 Importing。请注意,此操作必须以 root 用户身份执行,否则将无效。因此,拥有根用户身份的启动脚本是最容易做到的地方。如果这样做,在调用邮局主管之前,还应该在启动脚本中设置以下环境变量:

export PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
export PG_OOM_ADJUST_VALUE=0

这些设置将使 Postmaster 子进程在正常的 OOM 分数调整为零的情况下运行,因此 OOM 杀手仍然可以根据需要定位它们。如果希望子进程与其他一些 OOM 分数调整一起运行,则可以为PG_OOM_ADJUST_VALUE使用其他值。 (也可以省略PG_OOM_ADJUST_VALUE,在这种情况下它默认为零.)如果您未设置PG_OOM_ADJUST_FILE,则子进程将以与邮局主管相同的 OOM 分数调整运行,这是不明智的,因为要确保邮局局长有一个优先设置。

较早的 Linux 内核不提供/proc/self/oom_score_adj,但可能具有相同功能的早期版本/proc/self/oom_adj。除了禁用值为-17而不是-1000之外,此方法均相同。

Note

据报道,某些供应商的 Linux 2.4 内核具有 2.6 overcommit sysctl参数的早期版本。但是,在没有相关代码的 2.4 内核上将vm.overcommit_memory设置为 2 会使情况更糟,而不是更好。建议您先检查实际的内核源代码(请参见文件mm/mmap.c中的函数vm_enough_memory)以验证内核支持什么,然后再在 2.4 安装中尝试执行此操作。 overcommit-accounting文档文件的存在不应被视为该功能存在的证据。如有任何疑问,请咨询内核 maven 或您的内核供应商。

18 .4.5. Linux 大页面

与 PostgreSQL 一样,使用大的连续页可以减少使用大块连续内存时的开销,尤其是当使用大的shared_buffers值时。要在 PostgreSQL 中使用此功能,您需要一个带有CONFIG_HUGETLBFS=yCONFIG_HUGETLB_PAGE=y的内核。您还必须调整内核设置vm.nr_hugepages。要估算所需的大页面数量,请在未启用大页面的情况下启动 PostgreSQL,并使用/proc文件系统检查 postmaster 的VmPeak值以及系统的大页面大小。可能看起来像:

$ head -1 $PGDATA/postmaster.pid
4170
$ grep ^VmPeak /proc/4170/status
VmPeak:  6490428 kB
$ grep ^Hugepagesize /proc/meminfo
Hugepagesize:       2048 kB

6490428/2048大约为3169.154,因此在此示例中,我们至少需要3170个大页面,可以通过以下方式设置:

$ sysctl -w vm.nr_hugepages=3170

如果计算机上的其他程序也需要大页面,则较大的设置将是适当的。别忘了将此设置添加到/etc/sysctl.conf,以便重新启动后重新应用。

有时内核无法立即分配所需数量的大页面,因此可能有必要重复该命令或重新引导。 (重新启动后,应立即将机器的大部分内存转换成大页.)要验证大页分配情况,请使用:

$ grep Huge /proc/meminfo

也可能需要通过 sysctl 设置vm.hugetlb_shm_group来授予数据库服务器的 os 用户使用大页面的权限,和/或使用ulimit -l来授予锁定内存的权限。

PostgreSQL 中大页面的默认行为是在可能的情况下使用它们,而在失败时退回到普通页面。要强制使用大页面,您可以在postgresql.conf中将huge_pages设置为on。请注意,如果没有足够大的页面,使用此设置的 PostgreSQL 将无法启动。

有关 Linux 大页面功能的详细说明,请参见https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt