PostgreSQL10.1手冊_部分III.伺服器管理_第18章伺服器設定和操作_18.4.管理核心資源

李博bluemind發表於2018-10-02

18.4. 管理核心資源

PostgreSQL某些時候會耗盡作業系統的各種資源限制,當同一個系統上執行著多個拷貝的伺服器或在一個非常大的安裝中時尤其如此。本節解釋了PostgreSQL使用的核心資源以及你可以採取的用於解決核心資源消耗相關問題的步驟。

18.4.1. 共享記憶體和訊號量

PostgreSQL需要作業系統提供程式間通訊(IPC)特性, 特別是共享記憶體和訊號量。Unix驅動的系統通常提供 System V IPC、 POSIX IPC,或者兩者都有。 Windows有它自己的這些功能的實現,這裡不討論。

完全缺少這些功能通常表現為伺服器啟動時的Illegal system call錯誤。這種情況下,除了重新配置核心之外別無選擇。PostgreSQL沒有它們就不能工作。 不過,在現代作業系統中這種情況是罕見的。

在啟動伺服器時,PostgreSQL通常分配少量的System V共享記憶體, 和大量的POSIX (mmap)共享記憶體。另外, 在伺服器啟動時會建立大量訊號量,這些訊號量可以是System V或POSIX風格。 目前,POSIX訊號量用於Linux和FreeBSD系統,而其他平臺則使用System V訊號量。

注意

PostgreSQL 9.3之前,只使用了System V共享記憶體, 所以啟動伺服器所需的System V共享記憶體的數量更大一些。 如果你在執行著一個老版本的伺服器,請參考該伺服器版本的文件。

System V IPC特性通常受系統範圍分配限制的限制。 當PostgreSQL超出了這些限制之一時,伺服器會拒絕啟動並且並且留下一條有指導性的錯誤訊息,其中描述了問題以及應該怎麼做(又見第 18.3.1 節)。相關的核心引數在不同系統之間的命名方式一致,表 18.1給出了一個概述。不過,設定它們的方法卻多種多樣。下面給出了對於某些平臺的建議:

表 18.1. System V IPC引數

名稱 描述 執行一個PostgreSQL例項所需的值值
SHMMAX 共享記憶體段的最大尺寸(位元組) 至少 1kB,但是預設值通常要高一些
SHMMIN 共享記憶體段的最小尺寸(位元組) 1
SHMALL 可用共享記憶體的總量(位元組或頁面) 如果是位元組,同SHMMAX;如果是頁面, 為ceil(SHMMAX/PAGE_SIZE),加上其他應用程式的空間
SHMSEG 每個程式的最大共享記憶體段數目 只需要 1 段,但是預設值高很多
SHMMNI 系統範圍內的最大共享記憶體段數目 SHMSEG外加其他應用的空間
SEMMNI 訊號量識別符號(即,集合)的最大數目 至少ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16)加上其他應用程式的空間
SEMMNS 系統範圍內的最大訊號量數目 ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) * 17外加其他應用的空間
SEMMSL 每個集合中訊號量的最大數目 至少 17
SEMMAP 訊號量對映中的項數 見文字
SEMVMX 訊號量的最大值 至少 1000 (預設值常常是 32767,如非必要不要更改)

PostgreSQL要求少量位元組的 System V 共享記憶體(在 64 位平臺上通常是 48 位元組) 用於每一個伺服器拷貝。在大多數現代作業系統上,這個量很容易得到。但是,如果你執行了很多個伺服器拷貝, 或者其他應用也在使用 System V 共享記憶體,可能需要增加SHMALL(系統範圍內 System V 共享記憶體的總量)。注意在很多系統上SHMALL是以頁面而不是位元組來度量。

不太可能出問題的是共享記憶體段的最小尺寸(SHMMIN),對PostgreSQL來說應該最多大約是 32 位元組(通常只是1)。而系統範圍(SHMMNI)或每個程式(SHMSEG)的最大共享記憶體段數目不太可能會導致問題,除非你的系統把它們設成零。

當使用System V訊號量時,PostgreSQL對每個允許的連線(max_connections)、每個允許的自動清理工作者程式(autovacuum_max_workers)和每個允許的後臺程式(max_worker_processes)使用一個訊號量, 以16個為一個集合。每個這種集合還包含第 17 個訊號量, 其中儲存一個magic number,以檢測和其它應用使用的訊號量集合的衝突。 系統裡的最大訊號量數目是由SEMMNS設定的, 因此這個值必須至少和max_connectionsautovacuum_max_workers再加max_worker_processes一樣大, 並且每 16 個連線外加工作者還要另外加一個(見表 18.1中的公式)。引數SEMMNI 決定系統中同一時刻可以存在的訊號量集合的數目限制。因此這個引數必須至少為ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16)。降低允許的連線數目是一種臨時的繞開失敗(來自函式semget)的方法,通常使用讓人混亂的措辭No space left on device

在某些情況下可能還有必要增大SEMMAP,使之至少與SEMMNS相近。 這個引數定義訊號量資源對映的尺寸,在其中每個連續的可用訊號量塊都需要一項。 每當一個訊號量集合被釋放,那麼它要麼會被加入到該與被釋放塊相鄰的一個現有項,或者它會被註冊在一個新對映項中。如果對映被填滿,被釋放的訊號量將丟失(直到重啟)。因此訊號量空間的碎片時間長了會導致可用的訊號量比應有的訊號量少。

semaphore undo有關的其他各種設定,如SEMMNUSEMUME 不會影響PostgreSQL

當使用POSIX訊號量時,所需的訊號量數量與System V相同, 即每個允許的連線(max_connections)、允許的自動清理工作程式 (autovacuum_max_workers)和允許的後臺程式 (max_worker_processes)一個訊號量。 在首選此選項的平臺上,POSIX訊號量的數量沒有特定的核心限制。

AIX

至少到版本 5.1 為止,不再需要對這些引數(例如SHMMAX)做任何特殊的配置,這看起來就像是被配置成允許所有記憶體都被用作共享記憶體。這是一種通常被用於其他資料庫(DB/2)的配置。

但是,可能需要修改/etc/security/limits中的全域性ulimit資訊,預設的檔案尺寸硬限制(fsize)和檔案數量(nofiles)可能太低。

FreeBSD

可以使用sysctlloader介面來改變預設配置。下列引數可以使用sysctl設定:

# sysctl kern.ipc.shmall=32768
# sysctl kern.ipc.shmmax=134217728
# sysctl kern.ipc.semmap=256

要讓這些設定在重啟之後也保持,請修改/etc/sysctl.conf

對於sysctl所關心的來說這些訊號量相關的設定都是隻讀的,但是可以在/boot/loader.conf中設定:

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

修改這些值後需要一次重啟讓新設定能生效。 (注意:FreeBSD 不使用SEMMAP。較老的版本 會接受並且忽略kern.ipc.semmap的設定,而較新的 版本會完全拒絕它)。

你可能也希望你的核心將共享記憶體鎖定在 RAM 中並且防止它被換頁到交換分割槽。這可以使用sysctl的設定 kern.ipc.shm_use_phys來完成。

如果通過啟用sysctlsecurity.jail.sysvipc_allowed執行在 FreeBSD jail 中,執行在不同 jail 中的postmaster應當被不同的作業系統使用者執行。這可以提高安全性,因為它阻止非 root 使用者干涉不同 jail 中的共享記憶體或訊號量,並且它允許 PostgreSQL IPC 清理程式碼正確地工作(在 FreeBSD 6.0 及其後的版本中,IPC 清理程式碼不能正確地檢測到其他 jail 中的程式,也不能阻止不同 jail 中的 postmaster 執行在相同的埠)。

FreeBSD 4.0 之前的版本的工作與OpenBSD相似(見下文)。

NetBSD

NetBSD 5.0 及其後的版本中,IPC 引數可以使用sysctl調整。例如:

$ sysctl -w kern.ipc.shmmax=16777216

要使這些設定在重啟後保持,請修改/etc/sysctl.conf

你可能也希望你的核心將共享記憶體鎖定在 RAM 中並且防止它被換頁到交換分割槽。這可以使用sysctl的設定 kern.ipc.shm_use_phys來完成。

NetBSD 5.0 以前的版本的工作與OpenBSD相似(見下文),除了那些引數應該用關鍵詞options設定而不是option

OpenBSD

當核心被編譯時,選項SYSVSHMSYSVSEM需要被啟用(它們預設值)。共享記憶體的最大尺寸由選項SHMMAXPGS(以頁面計)決定。下面展示了一個如何設定多個引數的例子:

option        SYSVSHM
option        SHMMAXPGS=4096
option        SHMSEG=256

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

你可能也希望你的核心將共享記憶體鎖定在 RAM 中並且防止它被換頁到交換分割槽。這可以使用sysctl的設定 kern.ipc.shm_use_phys來完成。

HP-UX

預設的設定可以滿足正常的安裝。在HP-UX 10 上,SEMMNS的出廠預設值是 128,這可能對大型資料庫站點太低。

IPC引數可以在Kernel Configuration → Configurable Parameters下的System Administration Manager(SAM)中被設定。當你完成時選擇Create A New Kernel

Linux

預設的最大段尺寸是 32 MB,並且預設的最大總尺寸是 2097152 個頁面。一個頁面幾乎總是 4096 位元組,除了在使用少見huge pages的核心配置中(使用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以 4kB 的頁面度量。

在更老的 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 中,預設的共享記憶體和訊號量設定已經足以應付大部分PostgreSQL應用。Solaris 現在將SHMMAX的預設值設定為系統 RAM的四分之一。要進一步調整這個設定,使用與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,你可能也需要提升該區的資源使用限制。更多關於projects 和prctl的資訊請見System Administrator`s Guide中的 “Chapter2: Projects and Tasks”。

18.4.2. systemd RemoveIPC

如果正在使用systemd,則必須注意IPC資源(共享記憶體和訊號量) 不會被作業系統過早刪除。從原始碼安裝PostgreSQL時,這尤其值得關注。 PostgreSQL釋出包的使用者不太可能受到影響,因為postgres使用者通常是作為系統使用者建立的。

控制當使用者完全退出時是否移除IPC物件。系統使用者免除。 此設定在死板的systemd中預設為on, 但某些作業系統分配預設為關閉。

當此設定開啟時,典型的觀察效果是PostgreSQL伺服器使用的訊號量物件在明顯隨機的時間被刪除, 從而導致伺服器崩潰,並顯示日誌訊息

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

不同型別的IPC物件(共享記憶體與訊號量,System V與POSIX)在systemd 中略有不同,因此可能會發現某些IPC資源不會像其他IPC資源一樣被刪除。 但依靠這些微妙的差異是不可取的。

登出使用者可能會作為維護工作的一部分發生,或者當管理員以 postgres使用者或類似名稱登入時手動發生,所以通常難以防止。

什麼是系統使用者是由/etc/login.defs中的 SYS_UID_MAX設定在systemd編譯時確定的。

打包和部署指令碼應該小心,通過使用useradd -r、 adduser --system或等價物來建立postgres使用者作為系統使用者。

或者,如果使用者帳戶建立不正確或無法更改,建議設定

RemoveIPC=no

/etc/systemd/logind.conf或其他適當的配置檔案中。

小心

至少要確保這兩件事中的一件,否則PostgreSQL伺服器將非常不可靠。

18.4.3. 資源限制

Unix類作業系統強制了許多種資源限制,這些限制可能干擾你的PostgreSQL伺服器的操作。尤其重要的是對每個使用者的程式數目的限制、每個程式開啟檔案數目的限制以及每個程式可用的記憶體的限制。這些限制中每個都有一個限制和一個限制。實際使用的是軟限制,但使用者可以自己修改成最大為硬限制的數目。而硬限制只能由root使用者修改。系統呼叫setrlimit負責設定這些引數。 shell的內建命令ulimit(Bourne shells)或limitcsh)被用來從命令列控制資源限制。 在 BSD 衍生的系統上,/etc/login.conf檔案控制在登入期間設定的各種資源限制。詳見作業系統文件。相關的引數是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伺服器為每個連線都使用一個程式, 所以你應該至少和允許的連線同樣多的程式,再加上系統其它部分所需要的程式數目。 通常這個並不是什麼問題,但如果你在一臺機器上執行多個伺服器,資源使用可能就會緊張。

開啟檔案的出廠預設限制通常設定為socially friendly的值, 它允許許多使用者在一臺機器上共存,而不會導致不成比例的系統資源使用。 如果你在一臺機器上執行許多伺服器,這也許就是你想要的,但是在專門的伺服器上, 你可能需要提高這個限制。

在另一方面,一些系統允許獨立的程式開啟非常多的檔案;如果不止幾個程式這麼幹,那系統範圍的限制就很容易被超過。如果你發現這樣的現像, 並且不想修改系統範圍的限制,你就可以設定PostgreSQL的 max_files_per_process配置引數來限制開啟檔案數的消耗。

18.4.4. Linux 記憶體過量使用

在 Linux 2.4 及其後的版本中,預設的虛擬記憶體行為對PostgreSQL不是最優的。由於核心實現記憶體過量使用的方法,如果PostgreSQL或其它程式的記憶體要求導致系統用光虛擬記憶體,那麼核心可能會終止PostgreSQL的 postmaster 程式(主伺服器程式)。

如果發生了這樣的事情,你會看到像下面這樣的核心訊息(參考你的系統文件和配置,看看在哪裡能看到這樣的訊息):

Out of Memory: Killed process 12345 (postgres).

這表明postgres程式因為記憶體壓力而被終止了。儘管現有的資料庫連線將繼續正常運轉,但是新的連線將無法被接受。要想恢復,PostgreSQL應該被重啟。

一種避免這個問題的方法是在一臺你確信其它程式不會耗盡記憶體的機器上執行PostgreSQL。 如果記憶體資源緊張,增加作業系統的交換空間可以幫助避免這個問題,因為記憶體不足(OOM)殺手(即終止程式這種行為)只有當實體記憶體和交換空間都被用盡時才會被呼叫。

如果PostgreSQL本身是導致系統記憶體耗盡的原因,你可以通過改變你的配置來避免該問題。在某些情況中,降低記憶體相關的配置引數可能有所幫助,特別是shared_buffers 和work_mem兩個引數。在其他情況中,允許太多連線到資料庫伺服器本身也可能導致該問題。在很多情況下,最好減小max_connections並且轉而利用外部連線池軟體。

在 Linux 2.6 及其後的版本中,可以修改核心的行為,這樣它將不會過量使用記憶體。儘管此設定不會阻止OOM 殺手被呼叫,但它可以顯著地降低其可能性並且將因此得到更魯棒的系統行為。這可以通過用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的情況下使用。它將 postmaster 程式的程式相關的OOM score adjustment值設定為-1000,從而保證它不會成為 OOM 殺手的目標。 這樣做最簡單的方法是在 postmaster 的啟動指令碼中執行

echo -1000 > /proc/self/oom_score_adj

並且要在呼叫 postmaster 之前執行。請注意這個動作必須以 root 完成,否則它將不會產生效果。所以一個被 root 擁有的啟動指令碼是放置這個動作最容易的地方。如果這樣做,你還應該在呼叫 postmaster 之前在啟動指令碼中設定這些環境變數:

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

這些設定將導致 postmaster 子程式使用普通的值為零的 OOM score adjustment 執行,所以 OOM 殺手仍能在需要時把它們作為目標。如果你想要子程式用某些其他 OOM score adjustment 值執行,可以為PG_OOM_ADJUST_VALUE使用其他的值(PG_OOM_ADJUST_VALUE也能被省略,那時它會被預設為零)。如果你沒有設定PG_OOM_ADJUST_FILE,子程式將使用和 postmaster 相同的 OOM score adjustment 執行,這是不明智的,因為重點是確保 postmaster 具有優先的設定。

更老的 Linux 核心不提供/proc/self/oom_score_adj,但是可能有一個具有相同功能的早期版本,它被稱為/proc/self/oom_adj。這種方式工作起來完全相同,除了禁用值是-17而不是-1000

注意

有些廠商的 Linux 2.4 核心被報告有著 2.6 過量使用sysctl引數的早期版本。不過,在沒有相關程式碼的 2.4 核心裡設定vm.overcommit_memory為 2 將會讓事情更糟。我們推薦你檢查一下實際的核心原始碼(見檔案mm/mmap.c中的vm_enough_memory函式),驗證一下這個是在你的核心中是被支援的, 然後再在 2.4 安裝中使用它。文件檔案overcommit-accounting的存在能當作是這個特性存在的證明。如果有疑問,請諮詢一位核心專家或你的核心廠商。

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以使用大頁面, 和/或賦予使用ulimit -l鎖定記憶體的許可權。

PostgreSQL中大頁面的預設行為是 儘可能使用它們並且在失敗時轉回到正常頁面。要強制使用大頁面,你可 以在postgresql.conf中把huge_pages設定成 on。注意此設定下如果沒有足夠的大頁面可用, PostgreSQL將會啟動失敗。

Linux大頁面特性的詳細描述可見https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.

本文轉自PostgreSQL中文社群,原文連結:18.4. 管理核心資源


相關文章