工程趣聞 2026 年 10 月 5 日

2026-10-05 — 頁表隨連線數線性膨脹:Postgres 共享記憶體的隱藏成本

primary=https://frn.sh/pagetables/ primary=https://lkml.rescloud.iu.edu/hypermail/linux/kernel/2201.2/03246.html primary=https://clickhouse.com/blog/huge-pages-clickhouse-managed-postgres primary=https://www.percona.com/blog/why-linux-hugepages-are-super-important-for-database-servers-a-case-with-postgresql/

頁表隨連線數線性膨脹:Postgres 共享記憶體的隱藏成本

Fernando Simões(frn.sh)· 2026-10-01

Linux 的頁表成本不是「約 1/512」就算完:每個位址空間都要有自己的一份 PTE,共享同一塊記憶體的行程越多,頁表就越逼近資料本身的大小。這個常被忽略的乘數,正是資料庫伺服器在連線數上升時被 OOM killer 帶走的原因之一。

原本的問題

x86_64 上每個 4 KiB 資料頁對應一個 8 byte 的 PTE,所以單一行程映射的頁表約為資料的 1/512。但如果 N 個位址空間映射同一頁,頁表成本就是 N/512;512 個行程映射相同的頁,頁表就和資料頁一樣大。

Khalid Aziz 在 mshare 的 RFC 信件中舉了實例:一台 512GB 記憶體的資料庫伺服器,300GB 的 SGA 被 1500 個以上的 client 共享,系統因 OOM 當機;最壞情況下光是 PTE 就要 878GB 以上。他提出的方向是新增 mshare() 系統呼叫,讓行程共享 PTE。

實測數字

PostgreSQL 的 shared_buffers 正好是這種形狀:一大塊共享記憶體,每個 backend 行程各自映射。ClickHouse 的 Kaushik Iska 在 2026-07-14 的文章中,用 r7i.4xlarge(128GB)、Postgres 16、shared_buffers = 32GB,讓每條連線完整掃過 15.6GB 的快取表,再讀 /proc/meminfo 的 PageTables:

連線數4KB 頁2MB huge pages
25789 MB18 MB
1003.06 GB58 MB
2006.12 GB111 MB

4KB 頁每條連線增加 31.1MB,與算式「15.6GB ÷ 4KB × 8 byte ≈ 31.2MB」吻合。同一台機器上,select-only 的 pgbench 在 100 個 client 下從 373,083 TPS 升到 418,087 TPS,差 12%。

Percona 的 Jobin Augustine 在 2021 年的測試只用 80 條連線、192GB 記憶體的機器,改用 HugePages 後頁表總量只有 61MB,先前則超過 25GB。

影響範圍

  • 跑 Postgres 的人:用 grep PageTables /proc/meminfo 看頁表佔用;用 grep HugetlbPages /proc/<postmaster pid>/status 確認 huge pages 真的生效,值為 0 代表已退回 4KB 頁。
  • 設定 huge_pages 的人:預設值 try 會無聲退回 4KB 頁,ClickHouse 的做法是設成 on,拿不到就拒絕啟動。
# 舊:預設 try,失敗時靜默退回 4KB
huge_pages = try
# 新:保留頁池後強制使用
huge_pages = 'on'
huge_page_size = 0   # 系統預設,2MB

huge pages 的代價

保留 huge pages 需要尚未碎片化的連續記憶體。ClickHouse 的文章直說,在負載下的機器上「同樣的請求常會失敗」,所以他們在開機早期就保留,並在配置前先 drop_caches 與 compact_memory。另外 Postgres 的共享記憶體段比 shared_buffers 大,該文在 32GB 的設定下量到 32.75GB 的段,因此要用 postgres -C shared_memory_size 量出實際大小再回推。

NUMA 機器是另一個變體:多份頁表可省遠端走訪,但要付記憶體與同步成本。原文引用 Mitosis 與 Hydra 兩篇論文說明這個取捨,本文未逐一查證其數字。

補充:原文作者推導 1/512 與 N/512 的算式屬其自述,本文以 ClickHouse 的實測表交叉驗證。

原始來源:frn.sh、LKML mshare RFC、ClickHouse、Percona


End of article
0
Would love your thoughts, please comment.x
()
x