16.5. 管理内核资源 #
一个大型PostgreSQL安装会很快耗尽各种操作系统资源限制。(在某些系统上,出厂默认值非常低,你甚至不需要真正“大型”的安装就会遇到问题。)如果你遇到过这类问题,请继续阅读。
16.5.1. 共享内存和信号量 #
共享内存和信号量统称为“System V IPC”(连同消息队列,但消息队列与 PostgreSQL无关)。几乎所有现代操作系统都提供这些特性,但并非所有系统都默认启用了它们或将其设置得足够大,尤其是有 BSD 血统的系统。(对于 QNX 和 BeOS 移植,PostgreSQL 为这些设施提供了自己的替代实现。)
完全缺少这些功能时,通常会在服务器启动时出现 Illegal system call 错误。在这种情况下,除了重新配置内核别无选择。没有它们,PostgreSQL 无法工作。
当PostgreSQL超出各种硬性IPC限制之一时,服务器会拒绝启动,并应留下带有指导性的错误消息,说明所遇到的问题以及应如何处理(另见第 16.3.1 节)。相关内核参数在不同系统上的命名基本一致,表 16.2给出了概览。不过,设置它们的方法却各不相同。下面给出一些平台上的建议。请注意,更改这些设置通常需要重启机器,甚至可能需要重新编译内核。
表 16.2. System V IPC参数
| 名称 | 描述 | 合理的值 |
|---|---|---|
SHMMAX | 共享内存段的最大尺寸(字节) | 250 kB + 8.2 kB * shared_buffers + 14.2 kB * max_connections,直至无穷大 |
SHMMIN | 共享内存段的最小尺寸(字节) | 1 |
SHMALL | 可用共享内存的总量(字节或页面) | 如果是字节,同SHMMAX;如果是页面,为ceil(SHMMAX/PAGE_SIZE) |
SHMSEG | 每个进程的最大共享内存段数目 | 只需要 1 段,但是默认值高很多 |
SHMMNI | 系统范围内的最大共享内存段数目 | 像SHMSEG外加其他应用的空间 |
SEMMNI | 信号量标识符(即,集合)的最大数目 | 至少 ceil(max_connections / 16) |
SEMMNS | 系统范围内的最大信号量数目 | ceil(max_connections / 16) * 17,并为其他应用保留空间 |
SEMMSL | 每个集合中信号量的最大数目 | 至少 17 |
SEMMAP | 信号量映射中的项数 | 见文本 |
SEMVMX | 信号量的最大值 | 至少 1000(默认值常常是 32767,如非必要不要更改) |
最重要的共享内存参数是
SHMMAX,即以字节计的共享内存段的最大尺寸。如果
shmget返回像Invalid argument这样的错误消息,可能是超出了这个限制。所需共享内存段的尺寸随请求的缓冲区数量(-B 选项)和允许的连接数量(-N 选项)而变化,尽管前者的影响最大。(作为临时解决办法,你可以调低这些设置来消除失败。)粗略估计,你可以用缓冲区数量乘以块大小(默认
8 kB)再加上充足的额外开销(至少半兆字节)来估算所需的段尺寸。你可能得到的任何错误消息都会包含失败分配请求的尺寸。
不太可能出问题的是共享内存段的最小尺寸(SHMMIN),对PostgreSQL来说应该最多大约是 256 kB(通常只是
1)。系统范围(SHMMNI)或每进程(SHMSEG)的最大共享内存段数目不会导致问题,除非你的系统把它们设成零。有些系统还对系统内共享内存的总量有限制;参见下面的平台特定说明。
PostgreSQL为每个允许的连接(-N 选项)使用一个信号量,每 16 个组成一组。每组还包含第 17 个信号量,其中存放一个“魔数”,用来检测与其他应用程序使用的信号量集的冲突。系统中的信号量最大数量由SEMMNS设置,因此它必须至少等于max_connections再加上每 16 个允许连接一个的额外信号量(见表 16.2中的公式)。参数SEMMNI决定系统中同时可以存在的信号量集的数量上限,因此它必须至少为ceil(max_connections / 16)。降低允许的连接数是失败时的一种临时变通办法,这种失败通常表现为
semget函数返回措辞令人困惑的No space
left on device。
在某些情况下,可能还需要增大SEMMAP,使其至少与
SEMMNS处于同一数量级。这个参数定义信号量资源映射的大小,映射中每个连续的可用信号量块都需要占用一项。每当一个信号量集合被释放时,它要么会并入与该释放块相邻的现有项,要么会登记为一个新的映射项。如果映射已满,被释放的信号量就会丢失(直到重启)。信号量空间的碎片化随时间推移可能导致可用信号量少于应有数量。
SEMMSL参数决定一个信号量集中可以包含多少个信号量,对于PostgreSQL,它必须至少为 17。
与“信号量撤销”有关的其他各种设置,如SEMMNU
和SEMUME,对PostgreSQL无关紧要。
- BSD/OS
共享内存. 默认只支持 4 MB 共享内存。请记住,共享内存是不可换页的,它被锁定在 RAM 中。要增加系统支持的共享内存量,可以在内核配置文件中加入下面的内容。
SHMALL值 1024 表示 4 MB 共享内存。以下设置把最大共享内存区域增加到 32 MB:options "SHMALL=8192" options "SHMMAX=\(SHMALL*PAGE_SIZE\)"
对于运行 4.3 或更高版本的用户,可能还需要把
KERNEL_VIRTUAL_MB增加到默认值248之上。所有修改完成后,重新编译内核并重启。对于运行 4.0 及更早版本的用户,可用
bpatch在当前内核中找到sysptsize值。该值是在引导时动态计算的。$
bpatch -r sysptsize0x9 = 9然后,在内核配置文件中把
SYSPTSIZE加为硬编码值。把你用bpatch找到的值增大。每想要 4 MB 额外共享内存就加 1。options "SYSPTSIZE=16"
sysptsize无法通过sysctl更改。信号量. 你可能需要增加信号量的数量。默认情况下,PostgreSQL分配 34 个信号量,这超过了系统默认总数 60 的一半。请在内核配置文件中设置你想要的值,例如:
options "SEMMNI=40" options "SEMMNS=240"
- FreeBSD
NetBSD
OpenBSD 编译内核时需要启用选项
SYSVSHM和SYSVSEM(默认已启用)。共享内存的最大尺寸由选项SHMMAXPGS(以页计)决定。下面展示了一个如何设置各参数的例子:options SYSVSHM options SHMMAXPGS=4096 options SHMSEG=256 options SYSVSEM options SEMMNI=256 options SEMMNS=512 options SEMMNU=256 options SEMMAP=256
(在NetBSD和 OpenBSD上,关键字实际上是单数形式的
option。)你可能还希望配置内核,把共享内存锁定在 RAM 中,防止其被换出到交换区。这可以通过
sysctl设置kern.ipc.shm_use_phys来实现。- HP-UX
默认设置通常足以满足普通安装的需求。在 HP-UX 10 上,
SEMMNS的出厂默认值为 128,对较大的数据库站点来说可能过低。可以在 System Administration Manager(SAM)的 → 中设置 IPC 参数。完成后选择 。
- Linux
在 2.2 内核中,默认的共享内存限制(
SHMMAX和SHMALL都是)是 32 MB,但可以在proc文件系统中更改(无需重启)。例如,要允许 128 MB:$echo 134217728 >/proc/sys/kernel/shmall$echo 134217728 >/proc/sys/kernel/shmmax你可以把这些命令放进引导时运行的脚本中。
另外,如果可用的话,也可以用
sysctl控制这些参数。找到名为/etc/sysctl.conf的文件,向其中加入如下行:kernel.shmall = 134217728 kernel.shmmax = 134217728
此文件通常在引导时被处理,但之后也可以显式调用
sysctl。其他参数对任何应用来说尺寸都已足够。如果你想亲自查看,可以看
/usr/src/linux/include/asm-和xxx/shmpara m.h/usr/src/linux/include/linux/sem.h。- MacOS X
在 OS X 10.2 及更早版本中,编辑文件
/System/Library/StartupItems/SystemTuning/SystemTuning并更改以下命令中的值: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
在 OS X 10.3 中,这些命令已被移到
/etc/rc中,必须在那里编辑。- SCO OpenServer
在默认配置中,每个段只允许 512 kB 共享内存,大约只够
-B 24 -N 12使用。要提高此设置,首先切换到目录/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 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。
- UnixWare
在 UnixWare 7 上,默认配置中共享内存段的最大尺寸是 512 kB。这大约够
-B 24 -N 12使用。要显示SHMMAX的当前值,运行/etc/conf/bin/idtune -g SHMMAX
它会显示当前值、默认值、最小值和最大值。要为
SHMMAX设置新值,运行/etc/conf/bin/idtune SHMMAX
value其中
value是你要使用的新值(以字节计)。设置SHMMAX之后,重建内核:/etc/conf/bin/idbuild -B
然后重启。
16.5.2. 资源限制
类 Unix 操作系统强制执行多种资源限制,它们可能干扰
PostgreSQL 服务器的运行。特别重要的是每用户进程数、每进程打开文件数以及每个进程可用内存量的限制。这些限制都各有“硬”限制和“软”限制。实际生效的是软限制,但用户可以把它提高到硬限制为止。硬限制只能由 root
用户更改。系统调用setrlimit负责设置这些参数。从命令行控制资源限制使用 shell 内建命令ulimit(Bourne shell)或limit(csh)。在 BSD 衍生的系统上,文件/etc/login.conf控制登录时设置的各种资源限制。细节参见操作系统文档。相关参数是
maxproc、openfiles和
datasize。例如:
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配置参数来限制打开文件的消耗。
16.5.3. Linux 内存过量分配
在 Linux 2.4 及更高版本中,默认的虚拟内存行为对
PostgreSQL来说不是最优的。由于内核实现内存过量分配的方式,如果其他进程的内存需求导致系统虚拟内存耗尽,内核可能终止PostgreSQL服务器(即
postmaster进程)。
如果发生这种情况,你会看到类似这样的内核消息(该去哪里找这种消息请查阅你的系统文档和配置):
Out of Memory: Killed process 12345 (postmaster).
这表明postmaster进程因内存压力而被终止。虽然现有的数据库连接会继续正常工作,但不会接受新连接。要恢复,需要重启PostgreSQL。
避免此问题的一种方法是把PostgreSQL 运行在这样一台机器上:你能确保其他进程不会把机器的内存耗尽。
在 Linux 2.6 及更高版本中,更好的解决方案是修改内核的行为,使其不“过量分配”内存。这可以通过 sysctl 选择严格的过量分配模式来完成:
sysctl -w vm.overcommit_memory=2
或者在/etc/sysctl.conf中加入等价的条目。你可能还想修改相关的设置vm.overcommit_ratio。细节见内核文档文件
Documentation/vm/overcommit-accounting。
据报告,一些厂商的 Linux 2.4 内核带有 2.6 过量分配 sysctl 的早期版本。然而,在没有相关代码的内核上把vm.overcommit_memory
设置为 2 会使情况变得更糟而不是更好。建议你在 2.4 安装上尝试此操作之前,检查实际的内核源代码(见文件mm/mmap.c中的函数vm_enough_memory)来验证你的副本支持什么。存在
overcommit-accounting文档文件并不能作为该特性存在的证据。如有疑问,请咨询内核专家或你的内核供应商。