PostgreSQL email list:nvm wal buffer

yzs87發表於2020-12-30

本文介紹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] %40iki.fi

[2] %40iki.fi

[3]

 

 

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) 
  0002-Use-WAL-segments-as-WAL-buffers.patch  (40K) 
   0003-Lazy-unmap-WAL-segments.patch  (2K) 
   0004-Speculative-map-WAL-segments.patch  (1K)  Download Attachment
   0005-Allocate-WAL-segments-to-utilize-hugepage.patch  (1K) 

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)

[2] how_to_choose_the_correct_memmap_kernel_parameter_for_pmem_on_your_system

[3] Persistent Memory Wiki

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) 
v2-0002-Non-volatile-WAL-buffer.patch  (53K) 
v2-0003-README-for-non-volatile-WAL-buffer.patch  (7K) 
nvwal-performance-s50.png  (39K) 
nvwal-performance-s1000.png  (40K) 
postgresql.conf  (1K) 

 

6、增加支援流複製

v4-0001-Support-GUCs-for-external-WAL-buffer.patch  (42K) 
v4-0002-Non-volatile-WAL-buffer.patch  (73K) 
v4-0003-walreceiver-supports-non-volatile-WAL-buffer.patch  (7K) 
v4-0004-pg_basebackup-supports-non-volatile-WAL-buffer.patch  (25K) 
v4-0005-README-for-non-volatile-WAL-buffer.patch  (9K) 

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 。會繼續跟蹤。

原文


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2746710/,如需轉載,請註明出處,否則將追究法律責任。

相關文章