PostgreSQL資料庫配置大頁

作者:小麥苗

Linux標準大頁和透明大頁參考:https://www。xmmup。com/linux-biaozhundayehetoumingdaye。html

為了保證物理記憶體能得到充分的利用,避免記憶體空間浪費,Linux把程序當前使用的記憶體部分載入到物理記憶體裡,而不使用的部分則暫不載入。PostMaster程序註冊共享記憶體時,系統只是分配一個虛擬的地址空間,並不直接分配物理記憶體。當有實際的記憶體訪問時,CPU才會將虛擬地址對映到物理記憶體的一個地址上。維護這個對映關係的就是PageTable,它負責將虛擬記憶體地址轉換成物理記憶體地址。

Linux的記憶體管理採取的是分頁存取機制:把較大的物理記憶體分為了一個個固定大小(4KB)的記憶體頁進行管理。每塊記憶體頁透過PageTable中的一個元組來維護虛擬/物理記憶體之間的對映。CPU為了提高虛擬/物理記憶體之間的轉換效率,也會在TLB中快取一定量的Page Table元組。

對於PostgreSQL這種多程序架構程式來說,當服務端使用的共享記憶體較大,且併發連線數較多時,由於作業系統對於每個程序都要維護單獨的記憶體對映,PageTable中的元組數目將會變得非常多,所佔用的記憶體大小也會特別大。

Linux為了應對這種場景,降低多程序下PageTable的記憶體消耗。自從2。6及以上核心版本提供了記憶體頁大小為2MB的管理方式,稱為Huge Page。如果使用Huge Page的話,相同物理記憶體使用量的情況下記憶體頁的數目變少,減少了PageTable元組的條目個數,從而降低了系統的記憶體佔用。

真實應用場景:某PG使用者將例項(shared_buffers=64GB)部署在一臺記憶體為256GB的ECS上,業務繁忙時ECS記憶體使用率為85%,PageTable佔用記憶體120GB。而開啟Huge Page後相同業務場景的記憶體使用率降低到50%以下,PageTable大小僅300M!

PG從9。4版本開始支援大頁,對一些連線數很大且記憶體較大的PostgreSQL資料庫,強烈建議配置大頁(Huge pages)。這不僅僅是因為大頁的效能會高一些,也是為了避免頁表過大。

PG配置大頁

當PostgreSQL使用大量連續的記憶體塊時,使用大頁面會減少開銷,特別是在使用大shared_buffers時。 要在PostgreSQL中使用此特性,您需要一個包含CONFIG_HUGETLBFS=y和CONFIG_HUGETLB_PAGE=y的核心。您還必須調整核心設定vm。nr_hugepages。要估計所需的大頁面的數量,請啟動PostgreSQL,而不啟用大頁面,並使用/proc檔案系統來檢查postmaster的匿名共享記憶體段大小以及系統的大頁面大小。

計算nr_hugepages數量

例如:

$ head -1 $PGDATA/postmaster。pid4170$ pmap 4170 | awk ‘/rw-s/ && /zero/ {print $2}’6490428K$ grep ^Hugepagesize /proc/meminfoHugepagesize: 2048 kB

6490428/2048大約是3169。154,因此在這個示例中你至少需要3170個大頁面,我們可以設定:

$ sysctl -w vm。nr_hugepages=3170

如果機器上的其他程式也需要大頁面,則更大的設定將是合適的。

也可以基於如下指令碼直接計算相應的HugePage的大小。

#!/bin/bashPGDATA=‘/pg13/pgdata’pid=`head -1 $PGDATA/postmaster。pid`echo ‘Pid: $pid’peak=`grep ^VmPeak /proc/$pid/status | awk ‘{ print $2 }’`echo ‘VmPeak: $peak kB’hps=`grep ^Hugepagesize /proc/meminfo | awk ‘{ print $2 }’`echo ‘Hugepagesize: $hps kB’hp=$((peak/hps))echo Set Huge Pages: $hpsysctl -w vm。nr_hugepages=$hp

這種配置一般針對於資料庫伺服器,就是隻跑了個PostgreSQL,如果還有其他應用程式也需要大頁,則需要合理設定。

不要忘記將此設定新增到/etc/sysctl。conf,以便在重啟後重新應用它。

echo 3170 > /proc/sys/vm/nr_hugepagescat >> /etc/sysctl。conf <<‘EOF’vm。nr_hugepages=3170EOFsysctl -p

透過此指令碼計算出大頁的大小,然後新增到/etc/sysctl。conf裡,sysctl -p生效。

配置引數huge_pages為try

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

postgres=# show huge_pages; huge_pages —————— try(1 row)

然後重新啟動PG資料庫。

查詢

有時候核心會無法立即分配想要數量的大頁面,所以可能有必要重複該命令或者重新啟動。 在重新啟動之後,會立即將大部分機器的記憶體轉換為大頁面。

要驗證巨大的頁面分配情況,請使用:

[pg13@lhrpg pgdata]$ cat /proc/meminfo | grep huge -i AnonHugePages: 243712 kBHugePages_Total: 300HugePages_Free: 144HugePages_Rsvd: 73HugePages_Surp: 0Hugepagesize: 2048 kB

可能還需要賦予資料庫伺服器的作業系統使用者許可權,讓他能透過sysctl設定vm。hugetlb_shm_group以使用大頁面,和/或賦予使用ulimit -l鎖定記憶體的許可權。

引數huge_pages

huge_pages (enum)

控制是否為主共享記憶體區域請求大頁。有效值是try(預設)、on以及off。

如果huge_pages被設定為try,則伺服器將嘗試請求使用大頁,但是如果請求失敗則會退回到預設的方式。如果OS沒有配置大頁或者配置的大頁小於PG所需要的大頁記憶體,那麼就會請求失敗。

如果為on,請求大頁失敗將使得伺服器無法啟動。例如:

[pg13@lhrpg pgdata]$ pg_ctl startwaiting for server to start。。。。2021-08-03 09:25:16。697 CST [11917] FATAL: could not map anonymous shared memory: Cannot allocate memory2021-08-03 09:25:16。697 CST [11917] HINT: This error usually means that PostgreSQL‘s request for a shared memory segment exceeded available memory, swap space, or huge pages。 To reduce the request size (currently 150585344 bytes), reduce PostgreSQL’s shared memory usage, perhaps by reducing shared_buffers or max_connections。2021-08-03 09:25:16。697 CST [11917] LOG: database system is shut down stopped waitingpg_ctl: could not start serverExamine the log output。

如果為off,則不會請求大頁。

當前,只有Linux和Windows上支援這個設定。在其他系統上這個引數被設定為try時,它會被忽略。

大頁面的使用會導致更小的頁面表以及花費在記憶體管理上的CPU時間更少,從而提高效能。

大頁在Windows上被稱為大頁面。要使用大頁面,需要為執行PostgreSQL的Windows使用者賬號分配Lock Pages in Memory的使用者許可權。可以使用Windows的組策略工具(gpedit。msc)來分配使用者許可權Lock Pages in Memory。為了在命令視窗以單程序(而不是Windows服務)的方式啟動資料庫伺服器,命令視窗必須以管理員身份執行或者禁用使用者訪問控制(UAC)。當UAC被啟用時,普通的命令視窗會在啟動時收回使用者許可權Lock Pages in Memory。

注意這種設定僅影響主共享記憶體區域。Linux、FreeBSD以及Illumos之類的作業系統也能為普通記憶體分配自動使用大頁(也被稱為“超級”頁或者“大”頁面),而不需要來自PostgreSQL的顯式請求。在Linux上,這被稱為“transparent huge pages”(THP,透明大頁)。已知這種特性對某些Linux版本上的某些使用者會導致PostgreSQL的效能退化,因此當前並不鼓勵使用它(與huge_pages的顯式使用不同)。

Huge Page使用建議

雖然Huge Page在一定場景下可以改善服務端記憶體使用過高的情況,但不是鼓勵所有的PG例項都使用大頁,盲目的開啟Huge Page可能引起服務端的效能下降。下面我們根據Huge Page的優缺點來分析下使用場景。

Huge Page優勢:

(1)CPU的TLB可以快取的物理地址空間更大,從而提升TLB的命中率,降低CPU負載;

(2)Huge Page使用的記憶體是不可交換(swap)的,沒有記憶體空間換入/換出的開銷;

(3)極大的減少了系統維護PageTable的記憶體開銷。

Huge Page劣勢:

(1)Huge Page使用的記憶體需要預先分配;

(2)Huge Page使用固定大小的記憶體區域,不會被釋放;

(3)對於寫密集型的場景,Huge Page會加大Cache寫衝突的發生機率。

所以強烈推薦PG例項開啟Huge Page的場景:共享記憶體使用較大(>=8GB)且連線數較多(>= 500),並且熱點資料分散。

不推薦PG例項開啟Huge Page的場景:寫業務密集,熱點資料集中且記憶體使用較小。

PG開啟Huge Page時的注意事項

(1)當配置引數huge_pages設定為on時,若PG啟動時需要註冊的共享記憶體大於作業系統提供的Huge Page大小時,資料庫將無法啟動。推薦將huge_pages引數設定為try,在此種場景下,PostMaster將會改為申請普通記憶體。

(2)修改shared_buffers/wal_buffers等共享記憶體相關的GUC引數時,需要重新計算作業系統所需的Huge Page數,以防服務端無法啟動或者部分大頁記憶體沒有被使用且無法釋放而造成浪費。

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