技術實踐丨PostgreSQL開啟Huge Page場景分析
PostgreSQL使用者經常發現,服務端在連線數較大的情況下,會出現系統記憶體消耗過多的情況,嚴重者可能會造成OOM。但是服務端配置的共享記憶體(shared_buffers,wal_buffers等)是一定的,為什麼記憶體會持續增加呢?這就與PostgreSQL的多程序架構有關了,下面我們來分析下。
1. 大規格PG例項記憶體使用率較高分析
為了保證實體記憶體能得到充分的利用,避免記憶體空間浪費,Linux把程序當前使用的記憶體部分載入到實體記憶體裡,而不使用的部分則暫不載入。PostMaster程序註冊共享記憶體時,系統只是分配一個虛擬的地址空間,並不直接分配實體記憶體。當有實際的記憶體訪問時,CPU才會將虛擬地址對映到實體記憶體的一個地址上。維護這個對映關係的就是PageTable,它負責將虛擬記憶體地址轉換成實體記憶體地址。
Linux的記憶體管理採取的是分頁存取機制:把較大的實體記憶體分為了一個個固定大小(4kB)的記憶體頁進行管理。每塊記憶體頁通過PageTable中的一個元組來維護虛擬/實體記憶體之間的對映。CPU為了提高虛擬/實體記憶體之間的轉換效率,也會在TLB中快取一定量的Page Table元組。
對於PostgreSQL這種多程序架構程式來說,當服務端使用的共享記憶體較大,且併發連線數較多時,由於作業系統對於每個程序都要維護單獨的記憶體對映,PageTable中的元組數目將會變得非常多,所佔用的記憶體大小也會特別大。
2. Huge Page改善措施
Linux為了應對這種場景,降低多程序下PageTable的記憶體消耗。自從2.6及以上核心版本提供了記憶體頁大小為2MB的管理方式,稱為Huge Page。如果使用Huge Page的話,相同實體記憶體使用量的情況下記憶體頁的數目變少,減少了PageTable元組的條目個數,從而降低了系統的記憶體佔用。
作為世界上最先進的開源資料庫,PostgreSQL也適配了Linux的Huge Page特性,服務端在註冊共享記憶體時,會通過配置引數huge_pages來決定是否申請大頁記憶體。
postgresql.conf:
huge_pages = on -- 註冊共享記憶體時必須使用大頁
huge_pages = try -- 註冊共享記憶體時首先考慮大頁,若系統提供的大頁記憶體不足時,則全部使用普通頁
huge_pages = off -- 註冊共享記憶體時不使用大頁
真實應用場景:某PG使用者將例項(shared_buffers = 64GB)部署在一臺記憶體為256GB的ECS上,業務繁忙時ECS記憶體使用率為85%,PageTable佔用記憶體120GB。而開啟Huge Page後相同業務場景的記憶體使用率降低到50%以下,PageTable大小僅300M!
3. PG例項開啟Huge Page操作步驟
(1)檢視作業系統的Huge Page大小grep Hugepage /proc/meminfo
(2)估算PostgreSQL例項需要的Huge Page使用量:128GB/2MB * 1.2 = 78643
(3)/etc/sysctl.conf中新增:vm.nr_hugepages = 78643
(4)重新載入系統配置引數:sysctl –p
(5)確認是否配置成功。可以看到Huge Page總數為78643
(6)確認PG配置檔案開啟huge_pages
(7)啟動PostgreSQL服務端,可以看到系統中的空閒Huge Page已經減少,部分大頁已經被共享記憶體使用。
4. 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的場景:寫業務密集,熱點資料集中且記憶體使用較小。
5.PG開啟Huge Page時的注意事項
(1)當配置引數huge_pages設定為on時,若PG啟動時需要註冊的共享記憶體大於作業系統提供的Huge Page大小時,資料庫將無法啟動。推薦將huge_pages引數設定為try,在此種場景下,PostMaster將會改為申請普通記憶體。
(2)修改shared_buffers/wal_buffers等共享記憶體相關的GUC引數時,需要重新計算作業系統所需的Huge Page數,以防服務端無法啟動或者部分大頁記憶體沒有被使用且無法釋放而造成浪費。