1、PostgreSQL中DETOAST操作緩存的實現分享人:廖書楠場景引入需求分析詳細設計性能測試1234目錄directory01場景引入場景引入1.1PostgreSQL中的DETOAST操作完整的大尺寸字段值(2KB).壓縮和拆分分片1TOAST操作解壓縮和重拼接DETOAST操作當一次查詢中多次涉及一個大尺寸字段的讀取時,需要反復執行DETOAST操作,極其費時分片2分片3分片4分片51.2實際場景在某次緊急排查中,為了找出滿足特定條件的告警數據,需要執行以下SQL:SELECT value FROM ZENAP_FM _ACTIVEALARM WHERE(value-alarmpath
2、-pathids ae381dea-1d16-4b2c-83f8-2db8fc68edb6“OR value-alarmpath-pathids 103ce679-ba2a-4db1-9d17-fdcd1614ef55“-.中間省略693條OR子句OR value-alarmpath-pathids d4b9bd96-9036-4344-a1b3-8571b0205d1b“)ORDER BY value-servertime DESC,value-id DESC LIMIT 1000 OFFSET 0;在某現實生產環境下的告警日志表:對于表中的每條value記錄,都需要重復執行696次DETO
3、AST操作,極其費時1.3解決方案實現面向DETOAST操作的緩存:在每次執行完DETOAST操作后將結果緩存起來,后續重復訪問直接從緩存中讀取,無需執行耗時的DETOAST操作,降低CPU開銷。在緩存中?讀取是直接返回執行DETOAST否02需求分析需求分析2.1DETOAST緩存池需求分析置換策略尺寸分布TOAST字段是變長字段,其尺寸差異較大,不能采用固定大小的緩存塊1多進程并發變長字段TOAST字段的尺寸分布是無法預先確定的,如果將緩存塊的尺寸和數量設置為固定值,可能會導致利用率低,帶來較大的空間浪費需要面對多種不同的查詢場景,不宜采取單一置換策略多進程并發讀取時,需考慮緩存的跨進程同
4、步問題2341.采用多級緩存鏈表+極大緩存區的設計3.動態置換策略機制,支持多種不同的置換策略1.變長字段2.尺寸分布3.置換策略4.多進程并發2.2設計方案03詳細設計詳細設計3.1總體架構設計DETOAST緩存池header0header9datadatadataheader0header9datadatadatausedLists:多級已用鏈表freeLists:多級空閑鏈表extCache:極大緩存區dataHash表映射3.2多級緩存鏈表header0header9datadatadataheader1datadatadata多級緩存鏈表:多級緩存鏈表是緩存池的核心數據結構。參考了P
5、ostgreSQL中AllocSetContext的實現,多級鏈表由多個雙向鏈表組成,每個雙向鏈表中存放不同尺寸的緩存塊,大小分別為2KB、4KB、8KB、.、512KB、1MB(第i級鏈表中每個緩存塊的大小為2KB);同時,每個雙向鏈表的鏈表頭之間也通過指針進行連接,從而形成多級鏈表。3.2多級緩存鏈表在DETOAST緩存池中有兩個多級緩存鏈表,分別是usedLists和freeLists,其中:usedLists稱為已用鏈表,用于存放已使用的緩存塊;freeLists稱為空閑鏈表,用來存放空閑緩存塊;在運行過程中,當緩存池接收到插入TOAST字段值的請求時,首先從freeLists中取出一
6、塊尺寸合適的空閑緩存塊,接著將TOAST字段值寫入到塊中,然后將該緩存塊插入到usedLists中。多級空閑鏈表多級已用鏈表取出空閑緩存塊插入寫入字段值3.3極大緩存區極大緩存區:為了應對極少數尺寸極大、多級緩存鏈表的最大緩存塊也無法容納的TOAST字段值而設計。dataTOAST字段值試圖插入到多級緩存鏈表中插入到極大緩存區中失敗,尺寸超過緩存塊大小上限3.4置換策略模塊設計參考Redis中的置換策略模塊設計,支持多種不同的置換策略,允許在運行時動態指定;將置換策略設置為緩存池內部的一個結構體,包括一系列的輔助數據結構和行為函數指針組;置換策略結構體ReplacePolicy.輔助結構體行為
7、函數指針組.緩存池初始化過程中,根據GUC參數的值,初始化為不同的置換策略LRU?LFU?FIFO?LRU雙向鏈表、哈希表LRU函數指針組FIFO隊列、FIFO函數指針組LFU雙向鏈表、哈希表、LFU函數指針組3.4置換策略模塊設計在緩存池執行操作的過程中,會通過置換策略結構體中的函數指針,去回調相應的置換策略行為函數:緩存池插入新塊時置換策略插入時行為函數調用刪除舊塊時置換策略刪除時行為函數調用查詢某塊時置換策略查詢時行為函數調用需要淘汰一塊時置換函數調用3.5自適應緩存調整機制header0datadataheader1datadatadatadatadatadatadatadatadat
8、aheader2data.datadata回收由于很少使用,空閑塊數量富余由于頻繁使用,空閑塊數量緊缺+datadata新增-Freesize空閑空間FreeLists空閑鏈表3.6跨進程緩存同步機制實現無效消息隊列postgres進程1DETOAST緩存池數據1postgres進程2DETOAST緩存池數據1數據2數據3.數據1數據1postgres進程2DETOAST緩存池數據1數據2數據3.執行刪除操作刪除數據1刪除緩存發送DETOAST無效消息,通知其他進程數據1已失效讀取無效消息刪除數據1刪除數據1一致3.7GUC參數為DETOAST緩存池增加了3個GUC參數:容量:指定DETOAS
9、T緩存池的總容量,取值范圍為50-4096(單位:MB);置換策略名:指定DETOAST緩存池使用的置換策略,如LRU、LFU、FIFO等;空閑因子:指定DETOAST緩存池的空閑因子,即觸發自適應緩存調整機制的閾值,取值范圍為0-0.4;以上3個GUC參數均可在postgresql.conf中動態指定運行值,DETOAST緩存池將根據所指定的參數進行初始化。04性能測試性能測試4.1性能測試使用前面所述的真實生產場景的數據,在48核96線程的華為Taishan2280服務器進行測試,在其他條件相同的情況下,對添加和未添加DETOAST緩存模塊的PostgreSQL14.5發行版源碼進行多次重復對比實驗,得出實驗結果如下所示:執行次數執行次數平均開銷平均開銷最小開銷最小開銷最大開銷最大開銷未添加緩存模塊159384121315841202305112218266添加緩存模塊后229119848118544122063平均時長平均時長最小時長最小時長最大時長最大時長未添加緩存模塊20.83秒20.67秒20.99秒添加緩存模塊后8.74秒8.71秒8.7秒DETOAST操作執行次數及消耗時鐘周期原SQL語句執行總耗時DETOAST操作cpu開銷降低99.01%查詢總時間開銷降低58%查詢性能提高238%本項目已在gitee上開源:https:/