16.5. 管理內核資源

一次大型PostgreSQL安裝會很容易耗盡各種操作系統的資源上限。 (在有些系統上,出廠設置低得你都不用一次"大型"安裝。) 如果你碰到這類問題,請繼續閱讀。

16.5.1. 共享內存和信號燈

共享內存和信號燈的正確叫法是"System VIPC" (還有消息隊列,不過對于PostgreSQL而言沒什麼關系。) 盡管所有現代操作系統都提供這個特性,但並不是所有系統缺省都打開它或者有足夠的資源,尤其是有 BSD 親源的系統。 (對于QNXBeOS移植,PostgreSQL自己提供這套機制的替換實現。)

完全缺少這些機制的表現通常是在服務器啟動的時候的 Illegal system call錯誤。 這時除了重新配置內核以外沒什麼可做的。 PostgreSQL 沒它們幹不了活。

如果 PostgreSQL 超出了這些IPC 資源的硬限制之一的時候就會拒絕啟動並且留下一條相當有啟發性的錯誤信息告訴你它碰到了什麼問題以及需要為它做些什麼。 (又見 Section 16.3.1。) 相關的內核參數在不同系統之間有著相對固定的術語;Table 16-2 是一個概況。 不過,設置它們的方法卻多種多樣。不過要注意的是,你可能最好重新啟動你的機器,或者還要重新編譯內核來修改這些設置。

Table 16-2. 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信號燈的最大值至少 1000 (缺省通常是32767,除非被要求,否則不要修改)

最重要的共享內存參數是 SHMMAX, 以字節記的共享內存段可擁有的最大尺寸。 如果你收到來自shmget的類似Invalid argument 這樣的錯誤信息,那麼很有可能是你超過限制了。 要求的共享內存段隨著請求的緩衝區數量(-B選項)和允許的連接數量(-N選項)的變化而變化,盡管前者是最重要的因素。 (因此,作為一種臨時的解決方法,你可以降低這些設置來繞過失敗。) 如果粗略地估計,你可以估計所需要的段尺寸是緩衝區數量乘以塊尺寸(缺省 8 kB)加上足夠的盈餘(至少半兆字節)。 任何錯誤信息都會包含分配失敗的尺寸。

不太可能出問題的是共享內存段的最小尺寸(SHMMIN), 對 PostgreSQL來說大約是 256 kB左右(通常只是 1),而系統範圍(SHMMNI)或每進程(SHMSEG) 最大共享內存段數量不應該會產生問題,除非你的系統把它們設成零。 有些系統還對系統裡的共享內存總量有限制;參閱下面平台相關的指導。

PostgreSQL 每個允許的聯接使用一個信號燈(-N選項), 以 16 個為一套。每套信號燈還包含第十七個信號燈, 它裡面存儲一個"magic number(標志數字)", 以檢測和其他應用使用的信號燈集衝突。 系統裡的最大信號燈數目是由SEMMNS設置的, 因此這個值應該至少和 max_connections 設置一樣大,並且每十六個聯接還要另外加一個。 (參閱Table 16-2 裡面的公式。) 參數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 裡面的。 要增加你的系統支持的共享緩衝區數目,向你的內核配置文件裡增加下面的行。 一個值為 1024 的 SHMALL 代表 4 M 共享內存。 下面的東西把共享內存區域增加到 32 MB:

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

對于運行 4.3 或者更新版本的人,你可能需要增大 KERNEL_VIRTUAL_MB, 超過缺省的 248。做完上面的修改之後,然後編譯內核並重起。

對于運行 4.0 或者更早的版本的,請用 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"

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

在 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

缺省配置時,只允許每段 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

然後重起。

16.5.2. 資源限制

Unix 類系統強制了許多資源限制,這些限制可能幹擾你的 PostgreSQL 服務器的運行。 這裡尤其重要是對每個用戶的進程數目的限制,每個進程打開文件數目, 以及每個進程可用的內存。 這些限制中每個都有一個"硬"限制和一個"軟"限制。 軟限制實際是管用的,但用戶可以自己修改成最大為硬限制的數目。 而硬限制是只能由 root 用戶修改的限制。 系統調用 setrlimit 負責設置這些參數。 shell 的內建命令 ulimit(Bourne shells) 或limitcsh) 就是用于在命令行上控制資源限制的。 在 BSD 衍生的系統上,文件/etc/login.conf 控制在登錄時對各種資源設置什麼樣的限制數值。參閱操作系統文檔獲取細節。 相關的參數是 maxprocopenfiles,和 datasize。 比如:

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

-cur 是軟限制,後面附加 -max 就可以設置硬限制。)

內核通常也有一些系統範圍的資源限制。

PostgreSQL 服務器每個聯接都使用一個進程, 所以你應該至少允許和聯接數相同的進程數,再加上你的系統其它部分所需要的數目。 通常這個並不是什麼問題,但如果你在一台機器上運行多個服務器,那你就要把事情理清楚。

打開文件數目的出廠缺省設置通常設置為"社會友好"數值,就是說允許許多用戶共存于一台機器, 而不會導致只使用系統資源的不當比例。如果你在一台機器上運行許多服務器,這也許就是你想要的,但是在特殊的服務器上,你可能需要提高這個限制。

問題的另外一邊,一些系統允許獨立的進程打開非常多的文件;如果有那麼幾個進程這麼幹,那系統範圍的上限就很容易達到。 如果你發現這樣的現象,並且不想修改系統範圍的限止, 你就可以把 PostgreSQLmax_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 只會讓事情更糟,而不是更好。 我們建議你檢查一下實際的內核源代碼(參閱文件 mm/mmap.c 裡面的 vm_enough_memory 函數), 核實一下這個是在你的版本裡存在的,然後再在 2.4 內核裡使用這個特性。 文檔文件 overcommit-accounting 的存在能當作是這個特性存在的證明。 如果有問題,請詢問你的內核供應商的專家。