Database : Why not MMAP ?
用 mmap
等於放棄對記憶體的細粒度控制:
- 無法執行非阻塞的記憶體存取。
- 「磁碟上」的呈現必須與「記憶體中」的呈現一致。
- 資料庫無法知悉記憶體中的 Pages 內容。
- 各種與 mmap 相關的 syscalls 都不具有可移植性。
以上是這張圖這麼告訴我們的。
我們先瞭解 PostgreSQL
是怎麼處理記憶體配置的。
早期 PostgreSQL
採用 sysv,在啟動時先分配。9.3 版本時,為大幅度降低對 sysv 的依賴而改用 mmap
。但 mmap
有其缺點,所以 9.4 版本時,額外支援動態分配記憶體。[1][2]
我們不能說 OS Cache 總是最好的。它可能非常擅長處理 Block-level caching,但因為無法重寫,因此無法做到細微操作。作業系統除了能收集基本的存取統計外,就無法再多做什麼。所以若要 PostgreSQL
這樣的高級資料庫完全拋棄自己的 Cache 而全用 OS Cache 也是不合理的。實際上,大多數 PostgreSQL
專家都建議只有一小部分可用的 RAM 應該用作 Buffer Cache,並且讓作業系統管理大部分記憶體是正確的。
所以 PostgreSQL
並不總是使用 mmap,而是有自己的 Buffer Cache,只是大部分仍是使用基於 mmap
的記憶體管理方式。
接著來看 MySQL
的實現。
MySQL
因為是可抽換引擎,所以這裡我們只討論 InnoDB。依據我先前撰寫的兩篇內容 [4][5],可以知道 MySQL
InnoDB 自帶 InnoDB Buffer Pool 管理自己的記憶體,這與 PostgreSQL
有很大的不同,各有優缺點。
我們也可由此延伸到 MySQL
處理連線的 session 配置,來進一步認識 mmap
的影響。
MySQL
處理連線時,每個連線都會依據 read_buffer_size (其一) 的設定,配置相對應的記憶體大小,預設是 128 KB。若記憶體配置軟體是 Glibc (通常是),從原始碼得知 [6],當配置 > 128 KB 的空間時 [6],呼叫方法會改為較重量的 mmap
,此時記憶體配置的速度會降低,且每條連線的記憶體佔用也比較大。所以 read_buffer_size 並不是愈大愈好,反而預設的 128 KB 可能才是最優解,又快又省記憶體。
補充資料
[1] 如何度量 Kernel Resources for PostgreSQL
[2] PostgreSQL Documentation: Chapter 19. Server Configuration
[3] Hacker News : Why not mmap?
[4] 淺談 MySQL / PostgreSQL 的 Double Buffering
[5] 淺談 MySQL / PostgreSQL 的 Double Buffering (續)
[6] glibc : malloc.c