PostgreSQL email list:nvm wal buffer
本文介紹NVM WAL BUFFER的email list,詳細瞭解開發者對此的討論,以此深入
瞭解機制。
1、Heikki
使用mmap()/msync()對映WAL檔案,替代WAL buffer。如果讀memory-mapped檔案有IO錯誤時,程式會通過SIGBUS殺掉。
重新閱讀了[1][2],使用WAL段檔案對映到記憶體作為WAL BUFFER,依賴於WAL檔案是否放在PM上切換CPU指令或者msync()用於持久化WAL記錄。
聽起來挺合理,但是我沒測試過。我會嘗試與NVM WAL BUFFER進行比對測試。現在,有點擔心對於每個段檔案mmap/munmap帶來的消耗。
同時提到記憶體對映 IO的SIGBUS問題,從壞的記憶體塊讀取時會有這個問題,向這個塊[3]寫時也有這個問題 。未來會處理這個問題。
[1] https://www.postgresql.org/message-id/83eafbfd-d9c5-6623-2423-7cab1be3888c%40iki.fi
[2] https://www.postgresql.org/message-id/2aec6e2a-6a32-0c39-e4e2-aad854543aa8%40iki.fi
[3] https://pmem.io/2018/11/26/bad-blocks.htm
https://www.postgresql.org/message-id/2aec6e2a-6a32-0c39-e4e2-aad854543aa8%40iki.fi
2、mmap/munmap帶來的消耗
mmap/munmap每個WAL段檔案的消耗與write一個block的消耗誰更大。mmap比read消耗大,但是減小系統呼叫又可以使mmap更具優勢 。這只是猜測,並不知道mmap真實消耗是多少。
我有一個不同想法,當重用一個段檔案時,會一次寫所有整個頁,段檔案的即使沒有讀取過,也會被重寫。但是使用mmap時就不會有這樣的行為了。只要想mapped頁寫一個位元組,老內容就會被載入到記憶體。VM頁在該點設定讀寫後,系統不知道將要寫整個頁。讀取回收檔案的老內容顯然代價太過糟糕。
當修改mapped區和write()時,對於write-back行為是否有所不同。不管哪種方式,同一個檔案同一個頁面都會被寫髒,但核心可能對何時寫回磁碟有不同行為,這對效能影響很大。
這個問題可以分為兩類:效能和一致性。程式的作者同樣憂慮這些問題,但是也沒有一個很好的答案。作者認為同一個檔案被多個後端程式呼叫mmap(flags | MAP_SHARED)對於PM和非PM裝置都是保持一致性的,但是還沒找到任何如規範檔案來證明。
作者在同一個mmaped檔案上做了一個小程式,呼叫memcpy和msync,並行的地址範圍不同,沒發現損壞的資料。但這也無妨確保一致性,如果有損壞,作者會放棄...
作者會測試Heikki所說的使用mmap和munmap對映每個段檔案,來看是否合理。
Mmap/munmap可伸縮性確實很差,但是不認為會影響我們,因為PG不是多執行緒。
針對mmap/munmap,這樣做有很多改進。即使現在,在快速儲存方面,使用open_datasync會更快(至少在O_DIRECT上)。WAL擴充套件是一個挑戰性問題。不修改IO方式,有很多地方可以優化以提升效能:
1)將WALWriteLock分成兩個鎖:一個用於寫,一個用於flush wal。現在,一個會話進行flush一個wal時,其他會話不能write wal,即使該wal位於其他段檔案。沒有必要這樣做。
2)XLogFlush()中刷寫WAL時不要將刷寫請求的大小增加到最大( cf "try to write/flush later additions to XLOG as well" in XLogFlush() ),可以顯著減小OLTP負載。在SATA盤上有意義,但是對於SSD來說影響較小。寫的多,持久鎖時間就更長,增加了事務提交的延遲,組織更多的WAL寫。
3)應該立即將所有的XLOG頁的writes刷寫會作業系統。現在,在OLTP負載中IO永遠不會再commit之前出現,也就是說在XLogWrite()和commit之間的完全是在浪費時間。
做了這幾點,猜想能有2-3倍的效能提升。但是不得不從根本上改變WAL write的IO方式。使用非同步IO,可以像18k一樣每秒持久化8kb的write。在我筆記本上,寫4k,就是22k。
當然這和PG的wal flush沒可比性,因為WAL 經常會重複寫最後一個block。但不會記錄到組提交裡。
NVM WAL BUFFER的path:
0001-Preallocate-more-WAL-segments.patch
(3K)
Download Attachment
0002-Use-WAL-segments-as-WAL-buffers.patch
(40K)
Download Attachment
0003-Lazy-unmap-WAL-segments.patch
(2K)
Download Attachment
0004-Speculative-map-WAL-segments.patch
(1K)
Download Attachment
0005-Allocate-WAL-segments-to-utilize-hugepage.patch
(1K)
Download Attachment
3、是否可以模擬PM用於測試
通過“memmap=nnG!ssG”核心引數使用DRAM模擬PM。參考[1]和[2]瞭解詳細模擬步驟。如果不起作用,檢查PM和DAX的核心配置選項,比如CONFIG_FOOBAR,是否配置正確。
[1] How to Emulate Persistent Memory Using Dynamic Random-access Memory (DRAM)
https://software.intel.com/en-us/articles/how-to-emulate-persistent-memory-on-an-intel-architecture-server
[2] how_to_choose_the_correct_memmap_kernel_parameter_for_pmem_on_your_system
https://nvdimm.wiki.kernel.org/how_to_choose_the_correct_memmap_kernel_parameter_for_pmem_on_your_system
[3] Persistent Memory Wiki
https://nvdimm.wiki.kernel.org/
4、對於mmap WAL效能的測試
針對PG12分別進行修改。通過pgbench進行壓測。 SSD上儲存WAL,map後的結果比原生PG效能差很多。VTune顯示CopyXLogRecordToWAL的memcpy動作消耗的CPU時間比原生的大的多。使用NVDIMM-N,ext4-dax儲存WAL,結果差不多,XLogInsert() 和XLogFlush()消耗的時間mmap和NVM WAL BUFFER的差不多 。在PM上通過mmap WAL段檔案作為WAL BUFFER是個很好的嘗試。但是該path可能還有bug,並不能說效能提升或者下降。
5、作者的NVM WAL BUFFER測試
通過pgbench,指定不同的-c/--client和-j/--job,資料量規模因子s=50或者1000.結果如下:
Results (s=50) :
==============
Throughput [10^3 TPS] Average latency [ms]
( c, j) before after before after
------- --------------------- ---------------------
( 8, 8) 35.7 37.1 (+3.9%) 0.224 0.216 (-3.6%)
(18,18) 70.9 74.7 (+5.3%) 0.254 0.241 (-5.1%)
(36,18) 76.0 80.8 (+6.3%) 0.473 0.446 (-5.7%)
(54,18) 75.5 81.8 (+8.3%) 0.715 0.660 (-7.7%)
Results (s=1000)
================
Throughput [10^3 TPS] Average latency [ms]
( c, j) before after before after
------- --------------------- ---------------------
( 8, 8) 37.4 40.1 (+7.3%) 0.214 0.199 (-7.0%)
(18,18) 79.3 86.7 (+9.3%) 0.227 0.208 (-8.4%)
(36,18) 87.2 95.5 (+9.5%) 0.413 0.377 (-8.7%)
(54,18) 86.8 94.8 (+9.3%) 0.622 0.569 (-8.5%)
每個規模因子下,負載和延遲都有所改進。負載在(c,j)=(36,18)下TPS最高。 S =1000案例下,提升百分比較大。規模因子大,對於同表和索引的競爭就小些,也就是加鎖和解鎖的操作較少。這種情況下WAL對效能更重要。
條件 :
1) 使用一個物理server,2個numa節點:PG繫結到node 0,pgbench到node 1,每個節點18個core,192GB的DRAM
2) PGDATA在nvme ssd上,pg_wal在互動6-in-1的NVDIMM-N上:都安裝在server端,node 0,都用ext4,NVDIMM-N被mounted時有“-o dax”
3) 新增nvwal_path和nvwal_size引數到postgresql.conf中
步驟:
對每個(c,j)都做三次,然後取平均值:
(1) Run initdb with proper -D and -X options; and also give --nvwal-path and --nvwal-size options after patch
(2) Start postgres and create a database for pgbench tables
(3) Run " pgbench -i -s ___" to create tables (s = 50 or 1000)
(4) Stop postgres, remount filesystems, and start postgres again
(5) Execute pg_prewarm extension for all the four pgbench tables
(6) Run pgbench during 30 minutes
pgbench command line
====================
$ pgbench -h /tmp -p 5432 -U username -r -M prepared -T 1800 -c ___ -j ___ dbname
I gave no -b option to use the built-in "TPC-B (sort-of)" query.
軟體
========
- Distro: Ubuntu 18.04
- Kernel: Linux 5.4 (vanilla kernel)
- C Compiler: gcc 7.4.0
- PMDK: 1.7
- PostgreSQL: d677550 (master on Mar 3, 2020)
硬體
========
- System: HPE ProLiant DL380 Gen10
- CPU: Intel Xeon Gold 6154 (Skylake) x 2sockets
- DRAM: DDR4 2666MHz {32GiB/ch x 6ch}/socket x 2sockets
- NVDIMM-N: DDR4 2666MHz {16GiB/ch x 6ch}/socket x 2sockets
- NVMe SSD: Intel Optane DC P4800X Series SSDPED1K750GA
P atch
v2-0001-Support-GUCs-for-external-WAL-buffer.patch
(36K)
Download Attachment
v2-0002-Non-volatile-WAL-buffer.patch
(53K)
Download Attachment
v2-0003-README-for-non-volatile-WAL-buffer.patch
(7K)
Download Attachment
nvwal-performance-s50.png
(39K)
Download Attachment
nvwal-performance-s1000.png
(40K)
Download Attachment
postgresql.conf
(1K)
Download Attachment
6、增加支援流複製
v4-0001-Support-GUCs-for-external-WAL-buffer.patch
(42K)
Download Attachment
v4-0002-Non-volatile-WAL-buffer.patch
(73K)
Download Attachment
v4-0003-walreceiver-supports-non-volatile-WAL-buffer.patch
(7K)
Download Attachment
v4-0004-pg_basebackup-supports-non-volatile-WAL-buffer.patch
(25K)
Download Attachment
v4-0005-README-for-non-volatile-WAL-buffer.patch
(9K)
Download Attachment
7、其他人對NVM WAL BUFFER測試
資料檔案放到nvme ssd,WAL放到PM。使用下面兩種方式儲存WAL檔案:
1) NVM WAL BUFFER的分支,利用libpmem
2) 通過檔案系統介面訪問P,就是說將PM當做傳統的塊裝置。都是APP DIRECT方式使用PM。
進行了兩種insert場景:
1) 插入小記錄,記錄長度為24位元組
2) 插入大記錄,記錄長度328位元組
初衷是看下場景2)對於WAL寫密集下效能提升多大,但是發現場景1)NVM WAL BUFFER和原生PG相比有大概5%的效能提升,但是在2)有大概20%的效能衰減。
分析後,XlogFlush函式可以通過NVM WAL BUFFER提升,但是會影響CopyXlogRecordToWAL的效能。可能和PM比DRAM的memcpy延遲高有關。下面是測試結果:
Scenario A (length of record to be inserted: 24 bytes per record):
==============================
NVWAL SoAD
------------------------------------ ------- -------
Througput (10^3 TPS) 310.5 296.0
CPU Time % of CopyXlogRecordToWAL 0.4 0.2
CPU Time % of XLogInsertRecord 1.5 0.8
CPU Time % of XLogFlush 2.1 9.6
Scenario B (length of record to be inserted: 328 bytes per record):
==============================
NVWAL SoAD
------------------------------------ ------- -------
Througput (10^3 TPS) 13.0 16.9
CPU Time % of CopyXlogRecordToWAL 3.0 1.6
CPU Time % of XLogInsertRecord 23.0 16.4
CPU Time % of XLogFlush 2.3 5.9
8、作者對於328位元組效能衰減的回覆
對於328 位元組,作者測試沒有效能衰減,認為環境及安裝步驟等可能不一樣。
結果顯示N VM WAL BUFFER 比原始有更好效能:
步驟
在同一個機器上跑PG server 和 pgbench ,分別繫結到不同的 2 個 numa 節點。 S erver 端的 numa 節點用於 PM 和 P CI SSD :
01) 建立 PMEM namespace (sudo ndctl create-namespace -f -t pmem -m fsdax -M dev -e namespace0.0)
02) 在PM 上做 ext 4 檔案系統並以d ax 方式mount (sudo mkfs.ext4 -q -F /dev/pmem0 ; sudo mount -o dax /dev/pmem0 /mnt/pmem0)
03) PCIE SSD 也是ext 4 檔案系統,正常mount (sudo mkfs.ext4 -q -F /dev/nvme0n1 ; sudo mount /dev/nvme0n1 /mnt/nvme0n1)
04) /mnt/pmem0/pg_wal 作為 WAL 目錄
05) /mnt/nvme0n1/pgdata PGDATA 目錄
06) 執行 initdb 初始化 (initdb --locale=C --encoding=UTF8 -X /mnt/pmem0/pg_wal ...)
- Also give -P /mnt/pmem0/pg_wal/nvwal -Q 81920 in the case of Non-volatile WAL buffer
07) 在附件的 postgresql.conf 中刪除n vmwal_* 對於原始PG 測試
08) PG server 繫結到 NUMA node 0 (numactl -N 0 -m 0 -- pg_ctl -l pg.log start)
09) 建立 database (createdb --locale=C --encoding=UTF8)
10) 使用 pgbench 初始化 t , s=50 (pgbench -i -s 50)
11) ALTER TABLE pgbench_history ALTER filler TYPE character(300);)
- 使錶行大小為 328 bytes
12) pg_ctl -l pg.log -m smart stop
13) 重新mount PMEM 和 PCIe SSD
14) numactl -N 0 -m 0 -- pg_ctl -l pg.log start
15) 執行 pg_prewarm 預熱表 pgbench_* tables
16) 執行 pgbench on NUMA node 1 30 分鐘 (numactl -N 1 -m 1 -- pgbench -r -M prepared -T 1800 -c __ -j __)
- 執行預設的 tpcb-like 事務
執行3 次並取平均值。環境變數:
export PGHOST=/tmp
export PGPORT=5432
export PGDATABASE="$USER"
export PGUSER="$USER"
export PGDATA=/mnt/nvme0n1/pgdata
環境 :
- System: HPE ProLiant DL380 Gen10
- CPU: Intel Xeon Gold 6240M x2 sockets (18 cores per socket; HT disabled by BIOS)
- DRAM: DDR4 2933MHz 192GiB/socket x2 sockets (32 GiB per channel x 6 channels per socket)
- Optane PMem: Apache Pass, AppDirect Mode, DDR4 2666MHz 1.5TiB/socket x2 sockets (256 GiB per channel x 6 channels per socket; interleaving enabled)
- PCIe SSD: DC P4800X Series SSDPED1K750GA
- Distro: Ubuntu 20.04.1
- C compiler: gcc 9.3.0
- libc: glibc 2.31
- Linux kernel: 5.7 (vanilla)
- Filesystem: ext4 (DAX enabled when using Optane PMem)
- PMDK: 1.9
- PostgreSQL (Original): 14devel (200f610: Jul 26, 2020)
- PostgreSQL (Non-volatile WAL buffer): 14devel (200f610: Jul 26, 2020) + non-volatile WAL buffer patchset v4
作者按照Gang 的環境配置,得到原始 PG 比 N VM WAL BUFFER 效能好的結果。需要進一步分析。N VM WAL BUFFER 的 XL ogInsert 花費的時間較長。這個拖累了 X LogFlush 帶來的提升,整體上效能衰減了。 V T une 顯示 N VM WAL BUFFER 的 XLogInsert => XLogInsertRecord => CopyXLogRecordsToWAL => 中m emcpy 花費的時間較長,XLog Flush 時間較短。整體結果和Gang 一致。 PM 上的 W AL BUFFER 相對於D RAM 來說,m emcpy W AL 記錄時間長,因為現階段PM 延遲比 D RAM 大 。作為回報,N VM WAL BUFFER 減小了讓記錄命中裝置的時間,因為不需要將他們從緩衝區寫到其他地方,只需要將C PU cache 中內容持久化到 N VM 。會繼續跟蹤。
原文
https://www.postgresql-archive.org/PoC-Non-volatile-WAL-buffer-td6120484.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2746710/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL mail list patch:Non-volatile WAL BUFFERSQLAI
- 非易失性WAL BUFFER解析:flush WAL改造
- 非易失性WAL BUFFER解析:WAL日誌讀寫改造
- PostgreSQL的wal_buffersSQL
- PostgreSQL WAL解析:構建WAL記錄準備SQL
- 非易失性WAL BUFFER實現機制解析:預分配WAL檔案改造
- PostgreSQL DBA(14) - WAL基本術語SQL
- PostgreSQL 原始碼解讀(104)- WAL#1(Insert & WAL-heap_i...SQL原始碼
- PostgreSQL 原始碼解讀(105)- WAL#2(Insert & WAL-heap_i...SQL原始碼
- PostgreSQL 原始碼解讀(106)- WAL#3(Insert & WAL-heap_i...SQL原始碼
- PostgreSQL 原始碼解讀(107)- WAL#4(Insert & WAL-heap_i...SQL原始碼
- PostgreSQL 原始碼解讀(110)- WAL#6(Insert&WAL - XLogRe...SQL原始碼
- PostgreSQL 原始碼解讀(111)- WAL#7(Insert&WAL - XLogRe...SQL原始碼
- PostgreSQL 原始碼解讀(113)- WAL#9(Insert&WAL - CopyXL...SQL原始碼
- PostgreSQL DBA(15) - WAL檔案結構SQL
- PostgreSQL DBA(172) - PG 13(WAL activity in EXPLAIN)SQLAI
- 【PG】PostgreSQL 預寫日誌(WAL)、checkpoint、LSNSQL
- PostgreSQL DBA(38) - PG 12 Connection slots and WAL sendersSQL
- 非易失性WAL BUFFER實現機制解析:checkpoint改造
- PostgreSQL DBA(89) - Linux(Buffer vs Cache)SQLLinux
- 圖解PostgreSQL--buffer的分配圖解SQL
- PostgreSQL DBA(16) - WAL segment file內部結構SQL
- PostgreSQL-PG體系結構之WAL(五)SQL
- PostgreSQL DBA(20) - WAL full-page-write淺析SQL
- PostgreSQL的xlog/Wal歸檔及日誌清理SQL
- 圖解PostgreSQL--local buffer的分配圖解SQL
- PostgreSQL啟動恢復透過checkpoint open wal檔案SQL
- 非易失性WAL BUFFER實現機制解析:日誌源切換
- 非易失性WAL BUFFER實現機制解析:啟動恢復流程改造
- PostgreSQL pg_rewind例項--could not find previous WAL record at %X/%XSQL
- PostgreSQL 原始碼解讀(112)- WAL#8(XLogCtrl資料結構)SQL原始碼GC資料結構
- PostgreSQL 原始碼解讀(109)- WAL#5(相關資料結構)SQL原始碼資料結構
- nvm
- PostgreSQL 原始碼解讀(140)- Buffer Manager#5(BufTableInsert函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(144)- Buffer Manager#9(RelationGetBufferForTuple函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(143)- Buffer Manager#8(BufTableHashCode函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(136)- Buffer Manager#1(ReadBufferExtended函式)SQL原始碼函式
- PostgreSQL 原始碼解讀(139)- Buffer Manager#4(StrategyGetBuffer函式)SQL原始碼函式