1. 程式人生 > 其它 >KingbaseES垃圾回收引數優化之maintenance_work_mem

KingbaseES垃圾回收引數優化之maintenance_work_mem

maintenance_work_mem 引數說明與vacuum過程

maintenance_work_mem , autovacuum_work_mem。

如果沒有設定autovacuum_work_mem,預設值是-1,則使用maintenance_work_mem的設定值。

首先這部分記憶體最大的用處是用於vacuum程序操作。過程如下:

(1) 從指定的表中獲取每個表。
(2) 獲取表的ShareUpdateExclusiveLock鎖。該鎖允許從其他事務中讀取。
(3) 掃描所有頁面以獲取所有死元組,必要時凍結舊元組。
(4) 如果存在死元組,則刪除指向相應死元組的索引元組。
(5) 對錶的每一頁執行以下任務,步驟 (6) 和 (7)。
(6) 移除死元組並重新分配頁面中的活元組。
(7) 更新目標表各自的FSM和VM。
(8) 通過 index_vacuum_cleanup() 函式清理索引。
(9) 如果最後一頁沒有任何元組,則截斷最後一頁。
(10) 更新與目標表的vacuum處理相關的統計資訊和系統目錄。
(11) 更新與vacuum處理相關的統計和系統目錄。
(12) 如果可能,刪除不必要的檔案和阻塞頁面。

首先,資料庫掃描一個目標表以構建一個死元組列表,並在可能的情況下凍結舊元組。該列表儲存在本地記憶體中的autovacuum_work_mem或maintenance_work_mem中。凍結處理又分慵懶模式和飢餓模式,這裡不做贅述。
掃描後,資料庫通過引用死元組列表來刪除索引元組。 此過程在內部稱為“清理階段”。不用說,這個過程是昂貴的。在KingbaseESV8R6 或更高版本中,如果目標索引為 B-tree,則是否執行清理階段由配置引數Vacuum_cleanup_index_scale_factor決定。

當maintenance_work_mem已滿且掃描未完成時,資料庫進行步驟(4)至(7);然後返回步驟(3)並進行餘數掃描。也就是開始INDEX的掃描,當所有索引都掃描並清理了一遍後,繼續從剛才的記憶體滿的點開始掃描表。如此反覆,當多次maintenance_work_mem滿後,會出現索引掃描多次。

如圖:vacuum掃描索引,刪除索引的過程。

(8)至(10)步驟在刪除索引後執行清理,並更新與每個目標表的vacuum處理相關的統計資訊和系統目錄。
此外,如果最後一頁沒有元組,則將其從表文件中截斷。

顯然,步驟中看出重要問題是autovacuum_work_mem太小,INDEX會被多次掃描,非常浪費資源,時間。對於一個大表,多次掃描索引的代價非常昂貴,特別是在表中有很多索引的情況下。如果maintenance_work_mem設定太低,甚至需要多次索引掃描。那將非常考驗效能。因此,需要將maintenance_work_mem設定得足夠高,這樣就避免多次索引掃描。VACUUM VERBOSE TABLE 可以看到詳情索引被掃描了幾次。

關聯重要提示:
1)客戶現場遇到的問題是autovacuum_work_mem或maintenance_work_mem記憶體太小會導致autovacuum程序忙不過來,直觀感受就是對於大表有很多dead_tuple的情況,last_autovacuum為空或者很久不觸發autovacuum程序工作。當調大maintenance_work_mem,問題得到解決。

2)maintenance_work_mem的總記憶體消耗等於maintenance_work_mem*autovacuum_max_workers。當然理論是不會達到記憶體上限。
這部分記憶體是隨用隨分配,並不是直接全部用掉maintenance_work_mem或autovacuum_work_mem設定的全部記憶體。也就是說maintenance_work_mem設定的是實際上限值。這部分記憶體不包括你可能手工發起的VACUUM或 CREATE INDEX操作所需的記憶體。那麼就要求maintenance_work_mem足夠高。注意autovacuum_max_workers程序的數量和表的數量相對應,如果autovacuum_max_workers設定3,那麼只能同時並行vacuum3張表,對於分割槽表將以子分割槽為單位進行vacuum。至此,有沒有發現大的伺服器記憶體和ssd儲存對於vacuum效能至關重要。

maintenance_work_mem的另外一個用途,它控制構建索引時使用的最大記憶體量。構建B樹索引時,必須對資料排序,如果要排序的資料在maintenance_work_mem記憶體中放置不下,它將會溢位到磁碟中。在執行CREATE INDEX命令之前,你可以在本地會話中使用SET命令臨時增加該值。``

maintenance_work_mem的記憶體空間優化

之前發了一篇文章討論沒有及時autovacuum的原因,現在補充一條原因,這是近期的發現。有時候即使該表觸及到了20%的閾值,autovacuum程序可能也沒有啟動,比如它正在忙於處理其他一些表,由於受到autovacuum_max_workers程序的影響,清理程序可能在該表觸及20%閾值之前就開始工作了,沒有多餘的程序或者記憶體空間再去執行後續觸及閾值的表的清理工作。

如果你確實有非常大的表,可以做一件事,將autovacuum_vacuum_scale_factor減少到一個更小的值。你可以在死亡元組到達表大小的1%時就清理,甚至是表大小的0.1%。還可以分別針對每個表進行配置,這樣可以規避vacuum造成的IO高峰的問題,與設定大的觸發閾值相比,更頻繁地清理表並每次只掃描一遍索引,與較少掃描表但每次掃描多遍索引相比,並不一定會節省I/O時間。然而,我們需要考慮對前臺程序的影響。但是別忘了特別是對於非常大的表,頻繁清理往往會顯著提升查詢效能,因為每次順序掃描掃的是全表,包括死亡元組的行。

建議將log_autovacuum_min_duration設定為非預設值,因為它將告訴你autovacuum程序正在做什麼工作,這對故障診斷很有用。把這個引數值設定為0,但會記錄autovacuum程序執行的每個操作,但是很可能生成巨大的日誌量,不建議這樣設定。建議把它設定成表級引數,這樣不僅能排查問題,還有效規避了日誌量巨大的問題。日誌訊息中,如果看到“index scans: 2”或更大的值,則表示maintenance_work_mem記憶體快用完了,應該考慮增加該配置值。

maintenance_work_mem的記憶體計算

設定maintenance_work_mem=1GB,最多有1GB的記憶體,用於記錄一次vacuum時,一次可儲存的垃圾tuple的tupleid,tupleid為6位元組長度。

1G可儲存約1.7億條dead tuple的tupleid。

test=# select 1024*1024*1024/6;
?column?
-----------
178956970
(1 row)

預設死亡元組約等於表大小的20%,觸發垃圾回收。

那麼1G總共能存下多大的含死亡元組的表呢?約8.9億條記錄的表。

test=# select 1024*1024*1024/6/0.2;
?column?
--------------------
894784850.00000000
(1 row)

總結

1、log_autovacuum_min_duration=0,表示記錄所有表autovacuum的統計資訊。這會使日誌量巨大,建議對大表單獨設定。

2、autovacuum_vacuum_scale_factor=0.01,表示1%的垃圾時,觸發自動垃圾回收。這會使垃圾回收提前量,前面提到了,如果多表同時發生autovauum,會受到垃圾回收最大程序的影響,所以最好在表級別設定此引數,以達到頻繁的執行autovacuum程序並不會發生io擁擠現象。最有效的作用是頻繁vacuum幫助順序掃描避免掃描過多死亡元組。

3、autovacuum_work_mem,maintenance_work_mem根據實際情況設定,確保不出現垃圾回收時多次INDEX SCAN的數值.可以表級別設定log_autovacuum_min_duration,在日誌中觀察INDEX SCAN的數量。或者手工vacuum verbose table也可看到。

4、當觸發垃圾資料閾值的表很多,尤其是大表的情況,建議增加autovacuum_max_workers,避免有的表autovacuum不及時,但要注意總記憶體消耗。

5、當出現了index scans: 超過1的情況:

5.1、需要增加autovacuum_work_mem,或maintenance_work_mem增加到當前autovacuum_work_mem乘以index scans數量即可。

5.2、或者調低autovacuum_vacuum_scale_factor到當前值除以index scans即可,目的是讓autovacuum儘可能早的工作。