PostgreSQL vacuum 核心原始碼機理
為了能全面理解PG整個vacuum的過程,專門繪製了下面一個完整的過程圖,用以記錄其核心原始碼實現機理。整個過程比較複雜。大致分為以下幾個部分:
一、pg_ctl
這個負責PG server起動,呼叫start_postmaster後,起動PG主server程式postmaster。後面任務交給postmaster來處理。
二、postmaster
負責起動autovacuum launcher,起動autovacuum launcher後臺程式後,控制權交給launcher。
三、autovacuum launcher和 autovacuum worker
這兩個程式的原始碼都在autovacuum.c中,autovacuum.c中的原始碼可以大致上為分兩個階段:
第一個階段:主要為launcher的職責。負責為將要起來工作的worker分配AutoVacuumShemStruct結構槽,並且選擇一個最近最少vacuum或者最需要凍結xid的DB。
然後將此dbid賦值給worker,併傳送訊號給postmaster,說已經準備好woker了,可以起動了。
第二個階段:主要為worker的職責。postmaster接收到launcher的訊號後,起動AutoVacuumShemStruct中狀態為startingwork的auto vacuum worker。
主要是工作是fork一個程式,並將pid賦值給此worker,然後發訊號給launcher,說你可以準備起下一個worker了。
進入autovacuum worker後:
1.首先收集需要vacuum或者analyze的表。需要vacumm的表的判斷依據是Dead Tuples的值超過:vacuum_threshold + vacuum_scale_factor * num_tuples。
需要analyze的表的判斷依據是DML的記錄超過此值:analyze_threshold + analyze_scale_factor*num_tuples。
2.找到第一個需要vacuum的表,並將此表的 vacuum option引數賦值給autovacuum worker,即MyWorkInfo結構體(指向AutoVacuumShemStruct中的worker)。
如cost_limit,cost_delay,cost_limit_base引數。其中cost_limit_base的值等於cost_limit的值。
3.調整每個在running 的worker的cost_limit值。worker中有cost_limit和cost_limit_base兩個變數。cost_limit和cost_limit_base的值,在剛開始沒有經過balance時,是相等的。
但是經過balance過,cost_limit的值會發生變化。而cost_limit_base的值基本上就是表級別用”alter table xxx set(autovacuum_vacuum_cost_limt=1000)”命令來設定的值。
設定好後,在balance過程中,cost_limit_base的值基本上不變。因此才在名字上加了”base”用於區別。如果沒有設定,cost_limit和cost_limit_base都是autovacuum_vacuum_cost_limit這個在postgresql.conf配置的值。
表級別的設定值優先順序高於postgresql.conf中定義的全域性值。balance時,參考cost_limit_base的值對每個running worker 的cost_limit進行調整。cost_limit最大值
不超過cost_limit_base,即需在[1,cost_limit_base]閉區間內。cost_limit值的意義其實就是每個毫秒時間內vacuum所能允許消耗的IO cost值。即:cost_limit/cost_delay。
而這個cost_limit/cost_delay又會被autovacuum_max_workers個workers平分掉,而不是簡單的做個限制。如果超過,就是最高以4倍的cost_delay來懲罰,這將導致vacuum過程嚴重變長。
詳細說明見”第6“步。
4.balance完成後,接著就用上面的cost_limit和cost_delay值去更新VacuumCostDelay和VacuumCostLimit這兩個值。並將VacuumCostBalance的值置為“0”。這三個值的意義在”第6“步中講。
5.接著去判斷此次發起的是哪種型別的vacuum: vacuum full 還是lazy vacuum。如果是vacuum full,相當於重建relation,需要AccessExclusiveLock。如果是lazy vacuum,
則是SharedUpdateExclusiveLock。lazy vacuum 還要判斷是否需要full scan。如果是full scan,需要更新pg_class中的relfrozenxid值。partial scan只清理dead tuple和compact free space。
請見另外一篇文章“PostgreSQL vacuum原理—vacuum揭秘”。
6.最後就是去scan heap了。按每個block依次遍歷。每遍歷一個block都需要 delay一次。在這裡上面“第4步”中的三個值就派上用場了。每次sleep的時間按公式:
msec=VacuumCostDelay*VacuumCostBalance/VacuumCostLimit
如果上面這個值大於4倍的VacuumCostDelay值,那麼msec就等於“4*VacuumCostDelay”。否則就按上面公式算出的值進行sleep。sleep完成後,將MyWorkInfo中的cost_limit和cost_delay
賦值給VacuumCostDelay,VacuumCostLimit,以適應balance過程。然後再次將VacuumCostBalance設定為“0”。
其中VacuumCostDelay和VacuumCostLimit基本上每次balance後就不變了。唯有VacuumCostBalance值是在整個block遍歷的過程中變化的,它的cost計算是根據當前page hit,page miss
以及page dirty來計算的,請見另外一篇文章“PostgreSQL Cost Based Vacuum探秘”。因此如果一個表的update,delete操作很高,那麼dead tuple就非常多,導致vacumm時,
VacuumCostBalance值變高。因此如果要加快vacuum,減少一個表在vacuum時的delay時間,只有把cost_limit的值提高,也就是postgresql.conf中autovacuum_vacuum_cost中的值調大,
才會使上面公式的值就小。
上面還是太理論了,還是有點難懂的。我舉個簡單的例子來說明下cost的計算:
假設當前有3個表需要vacuum,而且起了3個worker。每個表的autovacuum_vacuum_cost_limit都為預設值200,autovacuum_vacuum_cost_delay的值都為10ms。另外postgresql.conf中
配置的這兩個值也是預設值,分別為200和10ms。那麼cost_limit 的值就是:200/3=66。當然,如果在每個表的cost_limit_base都不同的情況下,計算會複雜點。總體思路就是cost_limit_base
大的表,分到的cost_limit值也大些。但是區間還是在”第3步”中的區間,即[1,cost_limit_base]。cost_limit的可配置範圍在[1,10000];cost_delay的值在[1,100],單位是ms。
計算公式我歸納如下:
cost_total=sum(cost_limit_base/cost_limit_delay),每個runing worker都加起來。
cost_avail=autovacuum_vacuum_cost_limit/autovacuum_vacuum_cost_delay,postgresql.conf中配置的值。
每個worker的cost_limit=max(min(cost_avail*cost_limit_base/cost_total,cost_limit_base),1)。所以上面的值代入,得到約為66。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/30088583/viewspace-1618496/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL vacuum原理—vacuum揭秘SQL
- PostgreSQL vacuum原理—啟動機制SQL
- PostgreSQL 原始碼解讀(127)- MVCC#11(vacuum過程-vacuum_rel函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(131)- MVCC#15(vacuum過程-lazy_vacuum_heap函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(132)- MVCC#16(vacuum過程-lazy_vacuum_index函式#1)SQL原始碼MVCC#Index函式
- PostgreSQL 原始碼解讀(128)- MVCC#12(vacuum過程-heap_vacuum_rel函式)SQL原始碼MVCC#函式
- PostgreSQL 原始碼解讀(133)- MVCC#17(vacuum過程-lazy_vacuum_index函式#2)SQL原始碼MVCC#Index函式
- PostgreSQL 原始碼解讀(264)- PG 14(Speeding up recovery and VACUUM)SQL原始碼
- PostgreSQL 原始碼解讀(126)- MVCC#10(vacuum過程)SQL原始碼MVCC#
- PostgreSQL的vacuum流程SQL
- 【Postgresql】VACUUM 垃圾回收SQL
- PostgreSQL 原始碼解讀(129)- MVCC#13(vacuum過程-vacuum_set_xid_limits函式)SQL原始碼MVCC#MIT函式
- PostgreSQL 原始碼解讀(134)- MVCC#18(vacuum過程-HeapTupleSatisfiesVacuum函式)SQL原始碼MVCC#APT函式
- PostgreSQL 原始碼解讀(125)- MVCC#9(vacuum-主流程)SQL原始碼MVCC#
- PostgreSQL vacuum可見性SQL
- PostgreSQL Cost Based Vacuum探秘SQL
- 新特性:postgresql的vacuum漫談SQL
- PostgreSQL VACUUM 之深入淺出 (一)SQL
- PostgreSQL VACUUM 之深入淺出 (二)SQL
- PostgreSQL VACUUM 之深入淺出 (三)SQL
- PostgreSQL 原始碼解讀(130)- MVCC#14(vacuum過程-lazy_scan_heap函式)SQL原始碼MVCC#函式
- PostgreSQL DBA(142) - PG 12(Monitoring PostgreSQL VACUUM processes)SQL
- PostgreSQL DBA(92) - PG 12 Improving VACUUMSQL
- PostgreSQL vacuum原理一功能與引數SQL
- MyBatis原始碼分析之核心處理層MyBatis原始碼
- PostgreSQL 原始碼解讀(135)- MVCC#19(vacuum過程-heap_execute_freeze_tuple函式)SQL原始碼MVCC#函式
- PostgreSQL DBA(143) - pgAdmin(Monitoring PostgreSQL VACUUM processes#2)SQL
- postgreSQL 12-2 vacuum-主流程SQL
- JVMTI Attach機制與核心原始碼分析JVM原始碼
- PostgreSQL 並行vacuum patch - 暨為什麼需要並行vacuum或分割槽表SQL並行
- 原始碼安裝postgresql原始碼SQL
- PostgreSQL 原始碼解讀(225)- Transaction(子事務處理)SQL原始碼
- PostgreSQL核心SQL
- 深入淺出VACUUM核心原理(中): index by passIndex
- Postgresql關於Vacuum的作用和操作方法,Vacuum full鎖表並生成新的relfilenodeSQL
- PostgreSQL MVCC 原始碼實現SQLMVC原始碼
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- external-attacher原始碼分析(2)-核心處理邏輯分析原始碼