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選項)的變化而變化, 儘管前者是最重要的因素。 (因此,作為一種臨時的解決方法,您可以降低這些設置來繞過失敗。) 如果粗略地估計,您可以估計所需要的段尺寸,在 Table 16-2 裡有建議。 任何您得到的錯誤訊息都會包含分配失敗的尺寸。

有些系統對系統裡面共享內存的總數(SHMALL)還有限制。 請注意這個數值必須足夠大,大到PostgreSQL 加上其它使用共享內存段的應用的總和。 (注意:SHMALL 在很多系統上是用頁面數,而不是字元數來計算的。)

不太可能出問題的是共享內存段的最小尺寸(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 裡面的。 要增加您的系統支援的共享緩衝區數目,向您的內核配置文件裡增加下面的行:

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

SHMALL 以 4KB 頁為單位計算,所以 1024 頁面代資料表 4 M 共享內存。 所以上面的東西把共享內存區域增加到 32 MB。 對於執行 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 修改。

信號燈. 您可能還需要增加信號燈的數量;系統預設的總數 60 只能允許大概 50 個 PostgreSQL 連接。 在內核配置文件裡設置您需要的值,比如:

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 裡面去了,必須在那裡編輯。 您需要重新啟動才能讓設置生效。請注意 /etc/rc 通常會被 OS X 更新覆蓋 (比如 10.3.6 到 10.3.7),所以每次更新後您可能都需要重新編輯。

在這個平台上,SHMALL 是用 4KB 頁來度量的。

SCO OpenServer

預設配置時,只允許每段 512KB 共享內存,大概只夠 -B 24 -N 12用的。 要增大設置,首先進入 /etc/conf/cf.d目錄。 要顯示目前的以字元記的 SHMMAX,執行

./configure -y SHMMAX

設置 SHMMAX的新值:

./configure SHMMAX=value

這裡 value 是您想設置的以字元記的新值。 設置完了以後SHMMAX重新製作內核

./link_unix

然後重起。

AIX

至少對於版本 5.1 而言,我們有必要為類似 SHMMAX 這樣的參數做特殊的配置, 因為這個參數可以配置為所有內容都當作共享內存使用。這就是類似 DB/2 這樣的資料庫常用的配置。

不過,我們可能有必要在 /etc/security/limits 裡面修改全局 ulimit ulimit 訊息,因為文件大小的預設硬限制(fsize)以及文件數(nofiles)可能太低了。

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://sunsite.uakom.sk/sunworldonline/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 的存在能當作是這個特性存在的證明。 如果有問題,請詢問您的內核供應商的專家。