PostgreSQL-14版本snapshot的幾點最佳化
最近在分析PostgreSQL-14版本效能提升的時候,關注到了Snapshots的這一部分。發現在PostgreSQL-14版本,連續合入了好幾個和Snapshots相關的patch。
並且,Andres Freund也透過這些改進顯著減少了已確定的快照可擴充套件性瓶頸,從而改進了Postgres處理大量連線的問題,因為在連線數很高時計算一個快照的代價是很昂貴的。(對於分析連線可擴充套件性的侷限性可以參考Andres Freund的這篇文章 )
本篇文章,我會結合Andres Freund的幾個patch進行一些分析,看看在PostgreSQL-14版本里對於Snapshots做的這部分最佳化。
在PostgreSQL裡是使用SnapshotData結構體的xip來記錄哪些事務正在執行中,正常情況下,對於普通的MVCC快照,xip記錄了所有執行中的事務ID。(除了快照是處於recovery狀態產生的,這個時候它為空)
typedef struct SnapshotData { TransactionId xmin; /* all XID < xmin are visible to me */ TransactionId xmax; /* all XID >= xmax are invisible to me */ TransactionId *xip; uint32 xcnt; /* # of xact ids in xip[] */ TransactionId *subxip; int32 subxcnt; /* # of xact ids in subxip[] */ ...
在PostgreSQL-14版本之前,每個PG程式都對應一個PGPROC結構、一個PGXACT結構,而從PostgreSQL-14版本開始,把PGXACT合到PGPROC裡面了。
一、最佳化一:在構建快照時不計算全域性 horizons
這個patch的地址為
為了使GetSnapshotData()具有更強的可伸縮性,它不能不檢視每個程式的xmin:儘管快照內容不需要在提交只讀事務或釋放快照時更改,但在這些情況下會修改程式的xmin。xmin修改的頻率很快,它會導致GetSnapshotData()中的許多快取丟失,儘管快照底層的資料沒有改變,尤其是在核心計數較高的系統中。這是GetSnapshotData()在大型系統上擴充套件性差的最重要原因。
這個提交其實只是刪除對PGXACT->xmin的訪問,讓GetSnapshotData()不再需要訪問xmins,這本身不會帶來顯著的改善,但是為後續的幾個最佳化都是針對GetSnapshotData()不需要訪問xmins去做的。
二、最佳化二:將PGXACT->xmin移回PGPROC
這個patch的地址為
早在2011年其實就已經發現了GetSnapshotData存在瓶頸,當時做的最佳化是把PGPROC裡面把快照需要的變數拆出來,放到PGXACT中,這樣資料結構小很多,可以裝到一個cpu cacheline中。
這個patch它把第一部分GetSnapshotData()不再需要的xmin移回了PGPROC。原本在PGXACT裡使用xmin的時候,它比PGXACT裡的其他成員更新更頻繁,進而導致cacheline有很多不必要的ping-pong,所以又將PGXACT->xmin移回了PGPROC結構體。
這幾句話大一看好像有點一頭霧水,什麼是cacheline,什麼是ping-pong。
這裡給大家大致解釋這幾個名詞,方便我們更好去理解,文章底部也有我參考的連結。
1、cacheline
記憶體是DRAM,速度慢,容量大。屬於CPU外部裝置,透過匯流排與CPU進行通訊。而cache 在 CPU內部,屬於片上硬體。所以記憶體的速度會遠遠慢於cache。
cache的單位是cacheline,是一塊連續的記憶體。以cacheline 64位元組為例。所有的cacheline 又劃到各個way下。row: 叫做set。columne: 叫做way
當CPU訪問一個記憶體的時候,透過記憶體中間的6bits定位在哪個set,再透過24bits定位響應的cacheline。
對同一塊cache不停的進行寫操作,會增加cache之間更新快取的花銷。包括不停的去重新整理主存的內容。快取的cacheline的state machine 頻繁的從 S -> I 狀態
2、ping-pong
Ping-pong是一種資料緩衝的手段(是一種資料傳輸技術),能夠同時利用兩個相同資料緩衝區達到資料連續傳輸的目的(物件型別可以是任意的),兩者交替地被讀和被寫,從而提高資料傳輸速率。
然後再去看開頭的那句話,是不是大致理解了,這個patch主要減少了在這個函式里使用xmin所導致的cache之間頻繁更新快取的花銷,對於高度併發、快照獲取量大、工作負載大的情況,僅此更改就可以顯著提高可伸縮性。
三、最佳化三:將PGXACT->vacuumFlags移動到ProcGlobal->vacuumFlags
這個patch的連結為
這個patch把PGXACT->vacuumFlags 移至ProcGlobal,增加了GetSnapshotData()經常需要的資料儲存在L2快取中的機會,L2快取位於CPU與記憶體之間的臨時儲存器,容量比記憶體小但交換速度快,二級快取容量大小決定了cpu的效能。
L1 L2 L3快取和記憶體的快慢關係,可以參考如下:
L1的存取速度:4個cpu時鐘週期 L2的存取速度:11個cpu時鐘週期 L3的存取速度:39個cpu時鐘週期 RAM的存取速度:107個cpu時鐘週期
可以看到,L2快取的速度比在記憶體裡快,因此這樣的改動,相當於加快了GetSnapshotData()執行的速度。
四、最佳化四:移動subxact資訊到ProcGlobal,刪除PGXACT
這個patch的連結為
與第三個最佳化的更改類似,這個patch增加了GetSnapshotData()經常需要的資料儲存在L2快取中的機會。在許多workload中,子事務是非常罕見的,這使得檢查的代價很小。
把PGXACT的所有成員都轉移了,所以不需要再保留它了,因此刪除了PGXACT結構體。
五、最佳化五: 引入正在進行的xid的密集陣列
這個patch的連結為
之前構建快照時,GetSnapshotData會遍歷procArray->pgprocnos找到所有存在的PGPROC、PGXACT結構,收集所有的xid,即透過pgprocnos拿到索引,透過索引在離散的allPgXact陣列中拿到xid。而現在的版本,其實改成了將xids單獨拿出來放到連續儲存的密集陣列中,來顯著提高其命中率。
六、最佳化六:使用xact完成計數器快取快照
這個patch的連結為
這個提交在VariableCacheData的結構體裡引入了xactCompletionCount(VariableCacheData是共享記憶體中的一個資料結構,用於跟蹤OID和XID賦值狀態),它跟蹤自伺服器啟動以來以某種形式完成的帶有xid(即可能修改了資料庫)的Top事務的數量。PostgreSQL-14版本僅用於檢查GetSnapshotData()是否需要重新計算快照的內容。只要當前的xactCompletionCount與最初構建快照時相同,就可以避免重新構建快照的內容。
這個改動的意圖很明顯了,前幾個最佳化都是讓計算快照變得更快/更可伸縮,而這個改動是:避免重新構建快照的內容,減少資源佔用。(也就是能不重新做快照就不做快照)。
參考列表
1.Improving Postgres Connection Scalability: Snapshots(Andres Freund)
https://www.citusdata.com/blog/2020/10/25/improving-postgres-connection-scalability-snapshots/#unfortunately-a-minimal-transaction-visibility-primer
2.cacheline
3.ping-pong機制
https://blog.csdn.net/chenyu201003/article/details/81449762
4.德哥的PostgreSQL 20200819當天程式碼 - 14 對比 13 高併發效能最佳化 資料對比 - get snapshot improve
https://github.com/digoal/blog/blob/master/202008/20200817_01.md
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69990629/viewspace-2923809/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 理解Maven中的SNAPSHOT版本和正式版本Maven
- 編寫Spark程式的幾個最佳化點Spark
- React 效能最佳化,你需要知道的幾個點React
- MongoDB3.0新版本幾點介紹MongoDB
- ABAP程式碼執行時間最佳化的幾點建議
- Java 的幾種版本Java
- sql最佳化的幾種方式SQL
- kafka的幾點Kafka
- 使用Gradle釋出SNAPSHOT版本到JCenter(oss.jfrog.org)Gradle
- #新炬學院分享#關於Oracle資料庫最佳化的幾點總結Oracle資料庫
- mysql最佳化通常使用的幾種方法MySql
- 透漏幾點面試的真相面試
- Oracle的幾點註記Oracle
- HTTP協議幾個版本的比較HTTP協議
- Snapshot--使用Snapshot來還原資料庫資料庫
- 【SQL最佳化】SQL最佳化的10點注意事項SQL
- SQL Server SnapshotSQLServer
- 自學 JAVA 的幾點建議Java
- laravel session的幾個特點LaravelSession
- MySQL中explain的幾點用法MySqlAI
- 幾個MQTT的知識點MQQT
- 人工智慧的幾點思考人工智慧
- 聊聊Spring Boot幾個版本的區別Spring Boot
- 建立Azure Blob Snapshot的指令碼指令碼
- 如何快速最佳化幾千萬資料量的訂單表
- MySql資料庫最佳化的幾條核心建議MySql資料庫
- 給系統最佳化記憶體的幾個技巧記憶體
- 原始碼版本控制的幾條簡單規則原始碼
- B+樹的幾點總結
- 最近關於工作的幾點思考
- 關於json的幾點思考JSON
- 有關專案的幾點思考
- 關於Decorator模式的幾點想法模式
- 手機網站的幾點注意網站
- 解決 / 最佳化問題的切入點
- 開發安全幾點
- webgl 系列 —— 繪製一個點(版本2、版本3、版本4、版本5)Web
- 【DG】之 Snapshot standby模式模式