天天看點

PostgreSQL 老濕機圖解平安科技遇到的垃圾回收"坑"

近日收到 平安科技 海安童鞋 那裡回報的一個問題,在生産環境使用postgresql的過程中,遇到的一個有點"不可思議"的問題。

一張經常被更新的表,通過主鍵查詢這張表的記錄時,發現需要掃描異常多的資料塊。

本文将為你詳細剖析這個問題,同時給出規避的方法,以及核心改造的方法。

文中還涉及到索引的結構解說,仔細閱讀定有收獲。

.1. 和長事務有關,我在很多文章都提到過,pg在垃圾回收時,隻判斷垃圾版本是否是目前資料庫中最老的事務之前的,如果是之後産生的,則不回收。

是以當資料庫存在長事務時,同時被通路的記錄被多次變更,造成一些垃圾版本沒有回收。

PostgreSQL 老濕機圖解平安科技遇到的垃圾回收"坑"

.2. pg的索引沒有版本資訊,是以必須要通路heap tuple擷取版本。

PostgreSQL 老濕機圖解平安科技遇到的垃圾回收"坑"

測試表

頻繁更新100條記錄

開啟長事務,啥也不幹

經過一段時間的更新,發現需要通路很多資料塊了。

觀察通路很多的塊是heap塊

送出長事務前,使用vacuum verbose可以看到無法回收這些持續産生的垃圾page(包括index和heap的page)。

送出長事務

等待autovacuum程序回收垃圾,delete half index page。

通路的資料塊數量下降了。

使用pageinspect觀察測試過程中索引頁的内容變化

建立extension

開啟長事務

測試60秒更新

觀察需要掃描多少資料塊

觀察索引頁, root=412, 層級=2

檢視root頁内容

檢視最左branch 頁内容

檢視包含最小值的最左葉子節點内容

檢視包含最小值的最右葉子節點内容

檢視這些葉子索引頁包含data='01 00 00 00 00 00 00 00'的item有多少條,可以對應到需要掃描多少heap page

2652與前面執行計劃中看到的2651對應。

等待autovacuum結束

觀察現在需要掃描多少塊

檢視現在的索引頁内容,half page已經remove掉了

再觀察索引頁内容,已經被autovacuum收縮了

src/backend/access/nbtree/nbtpage.c

contrib/pageinspect/btreefuncs.c

1. b-tree原理

<a href="https://yq.aliyun.com/articles/54437">https://yq.aliyun.com/articles/54437</a>

1. 頻繁更新的表,資料庫的優化手段

1.1 監控長事務,絕對控制長事務

1.2 縮小autovacuum naptime (to 1s) ,

1.3 如果事務釋放并且表上面已經出發了vacuum後,還是要查很多的page,說明index page沒有delete和收縮,可能是index page沒有達到compact的要求,如果遇到這種情況,需要reindex。

2. postgresql 9.6通過快照過舊徹底解決這個長事務引發的坑爹問題。

9.6 vacuum的改進如圖

PostgreSQL 老濕機圖解平安科技遇到的垃圾回收"坑"

如何判斷snapshot too old如圖

PostgreSQL 老濕機圖解平安科技遇到的垃圾回收"坑"

<a href="https://www.postgresql.org/docs/9.6/static/runtime-config-resource.html#runtime-config-resource-async-behavior">https://www.postgresql.org/docs/9.6/static/runtime-config-resource.html#runtime-config-resource-async-behavior</a>

3. 9.6的垃圾回收機制也還有改進的空間,做到更細粒度的版本控制,改進方法以前分享過,在事務清單中增加記錄事務隔離級别,通過隔離級别判斷需要保留的版本,而不是簡單的通過最老事務來判斷需要保留的垃圾版本。

祝大家玩得開心,歡迎随時來 阿裡雲促膝長談 業務需求 ,恭候光臨。

阿裡雲的小夥伴們加油,努力做 最貼地氣的雲資料庫 。