3.5. 管理内核资源

一次大型PostgreSQL安装会很容易耗尽各种操作系统的 资源上限.(在有些系统上,出厂设置低得你都不用一次"大型"安装.) 如果你碰到这类问题,请继续阅读.

3.5.1. 共享内存和信号灯

共享内存和信号灯的正确叫法是"System VIPC"( 还有消息队列,不过对于PostgreSQL而言没什么 关系.)尽管所有现代操作系统都提供这个特性,但并不是 所有系统缺省都打开它或者有足够的资源,尤其是有 BSD 亲源 的系统. (对于QNXBeOS移植? PostgreSQL自己提供这套 机制的替换实现.)

完全缺少这些机制的表现通常是在 postmaster 启动的时候的 Illegal system call错误.这时除了重新配置内核以外 没什么可做的 -- PostgreSQL 没它们干不了活.

如果 PostgreSQL 超出了这些IPC 资源的硬限制之一的时候 就会拒绝启动并且留下一条相当有启发性的错误信息告诉你它碰到了 什么问题以及需要为它做些什么. (又见 Section 3.3.1.) 相关的内核参数在不同系统之间有着相对固定的术语; Table 3-3 是一个概况.不过,设置它们的方法却 多种多样.不过要注意的是,你可能最好重新启动你的机器,或者还要 重新编译内核来修改这些设置.

Table 3-3. System V IPC参数

名字描述合理取值
SHMMAX最大共享内存段尺寸(字节)250kB + 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信号灯的最大值>= 255 (缺省通常是32767,除非被要求,否则不要修改)

最重要的共享内存参数是 SHMMAX, 以字节记的共享内存段可拥有的最大尺寸. 如果你收到来自shmget的类似Invalid argument 这样的错误信息,那么很有可能是你超过限制了. 要求的共享内存段随着请求的缓冲区数量(-B选项)和 允许的连接数量(-N选项)的变化而变化,尽管前者是 最重要的因素. (因此,作为一种临时的解决方法,你可以降低这些设置来绕过失败.) 如果粗略地估计,你可以估计所需要的段尺寸是缓冲区数量乘以块 尺寸(缺省 8 kB)加上足够的盈余(至少半兆字节). 任何错误信息都会包含分配失败的尺寸.

不太可能出问题的是共享内存段的最小尺寸(SHMMIN), 对 PostgreSQL来说大约是 256 kB左右(通常只是 1),而 系统范围(SHMMNI)或每进程(SHMSEG) 最大共享内存段数量不应该会产生问题,除非你的系统把它们设成零. 有些系统还对系统里的共享内存总量有限制;参阅下面平台相关的指导.

PostgreSQL 每个允许的联接使用一个信号灯 (-N选项), 以 16 个为一套.每套信号灯还包含第十七个信号灯, 它里面存储一个"magic number(标志数字)", 以检测和其他应用使用的信号灯集冲突. 系统里的最大信号灯数目是由SEMMNS设置的, 因此这个值应该至少和联接设置一样大,并且每十六个联接还要另外加一个. (参阅Table 3-3 里面的公式.) 参数SEMMNI决定 系统里一次可以存在的信号灯集的数目.因此这个参数至少应该为 ceil(max_connections % 16).降低允许的联接数目是一个临时的 绕开失败的方法,这个启动失败通常被来自函数semget() 的错误响应 "No space left on device"搞得很让人迷惑.

有时候还可能有必要增大SEMMAP,使之至少按照 SEMMNS配置.这个参数定义信号灯资源映射的尺寸, 可用的每个连续的信号灯块在这个映射中存放一条记录. 每当一套信号灯被释放,那么它要么会加入到该映射中一条相连的 已释放的块的入口中,要么注册成一条新的入口.如果映射填满了碎片, 那么被释放的信号灯就丢失了(除非重起).因此时间长信号灯空间的碎片 了会导致可用的信号灯比应该有的信号灯少.

SEMMSL 参数,决定一套信号灯里可以有多少信号灯,对于 PostgreSQL而言应该至少是 17.

许多设置与 "semaphore undo(信号灯恢复)"有关,比如 SEMMNUSEMUME,这些与 PostgreSQL无关.

BSD/OS

共享内存. 缺省时是只支持 4 MB 的共享内存.请记住共享内存是不能分页的;它是 锁在 RAM 里面的.要增加 postmaster 支持的共享缓冲区数目,向 你的内核配置文件里增加下面的行.一个值为 1024 的 SHMALL 代表 4 M 共享内存.下面的东西把共享内存区域增加到 32 MB∶

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

对于运行 4.1 或更新的版本的人,只需要做上面的修改, 然后编译内核并重起.对于运行 更早的版本的,请用 bpatch 找出当前内核的 sysptsize值.它是启动的时候自动计算的.

$ bpatch -r sysptsize
0x9 = 9

然后,把 SYSPTSIZE修改为在内核配置文件里的一个硬代码值. 用 bpatch 算出来的值,并且为你需要的每个额外的 4 MB 共享内存再加 1.

options "SYSPTSIZE=16"

sysptsize不能用 sysctl 修改.

信号灯. 你可能需要增加信号灯的数量.缺省时,PostgreSQL 分配 34 个信号灯.这个数量只是刚刚超过缺省的系统总数 60 的一半.

在内核配置文件里设置你需要的值,比如:

options "SEMMNI=40"
options "SEMMNS=240"
options "SEMUME=40"
options "SEMMNU=120"

FreeBSD
NetBSD
OpenBSD

编译内核时 需要把选项SYSVSHMSYSVSEM打开. (缺省是打开的.) 共享内存的最大尺寸是由选项SHMMAXPGS(以页计). 下面显示了一个如何设置这些参数的例子:

options         SYSVSHM
options         SHMMAXPGS=4096
options         SHMSEG=256

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

(在 NetBSDOpenBSD里,关键字实际上是单数的 option)

你可能原意使用 sysctl 设置将共享内存锁在 RAM 中以避免它们被交换出去,也即,kern.ipc.shm_use_phys

HP-UX

缺省设置看来对普通安装是足够的了. 在 HP-UX 10,SEMMNS的出厂缺省是 128, 可能对大的数据库节点来说太小了.

IPC可以在 System Administration Manager(系统管理器) (SAM)下面的 Kernel Configuration->Configurable Parameters 配置.你配置完了以后敲 Create A New Kernel选项.

Linux

在 2.2 内核里缺省的共享内存限制( SHMMAXSHMALL)都是 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/shmparam.h/usr/src/linux/include/linux/sem.h.

MacOS X

编辑文件 /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

这些值在 MacOS X 上的含义和前面列出的操作系统的含义相同。

SCO OpenServer

缺省配置时,只允许每段 512KB 共享内存,大概只够 -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

你要重起系统令修改生效.

又见 http://www.sunworld.com/swol-09-1997/swol-09-insidesolaris.html 获取关于 Solaris 里面的共享内存的信息.

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

然后重起.

3.5.2. 资源限制

Unix 类系统强制了许多资源限制,这些限制可能干扰你的 PostgreSQL 服务器的运行. 这里尤其重要是对每个用户的进程数目的限制,每个进程打开文件数目, 以及每个进程可用的内存. 这些限制中每个都有一个"硬"限制和一个"软" 限制. 软限制实际是管用的,但用户可以自己修改成最大为硬限制的数目. 而硬限制是只能由 root 用户修改的限制. 系统调用 setrlimit 负责设置这些参数. shell 的内建命令 ulimit(Bourne shells) 或limitcsh) 就是用于在命令行上控制资源限制的. 在 BSD 衍生的系统上,文件/etc/login.conf 控制在登录时对各种资源设置什么样的限制数值. 参阅 login.conf 获取细节. 相关的参数是 maxprocopenfiles,和 datasize. 比如:

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

-cur 是软限制,后面附加 -max 就可以设置硬限制.)

内核通常也有一些系统范围的资源限制.

PostgreSQL 服务器每个联接都使用一个进程, 所以你应该至少允许和联接数相同的进程数,再加上你的系统其它部分 所需要的数目.通常这个并不是什么问题,但如果你在一台机器上 运行多个服务器,那你就要把事情理清楚.

打开文件数目的出厂缺省设置通常设置为 "社会友好"数值,就是说允许许多用户共存于一台机器, 而不会导致只使用系统资源的不当比例.如果你在一台机器上运行许多 服务器,这也许就是你想要的,但是在特殊的服务器上,你可能需要提高 这个限制.

问题的另外一边,一些系统允许独立的进程打开非常多的文件; 如果有那么几个进程这么干,那系统范围的上限就很容易达到. 如果你发现这样的现象,并且不想修改系统范围的限止, 你就可以把 PostgreSQLmax_files_per_process 配置参数设置为你允许的 最大单进程打开文件数.