ao表的同步是個強同步的過程,資料在更新發生時即同步到mirror,primary和mirror時刻保持着資料一緻性。另一方面,事務送出時會更新ao表檔案的尾指針資訊,并同步到備庫。這樣事務送出後,mirror肯定可以看到所有已送出的資料。是以primary failover切換後ao表資料不會丢失,不影響事務的一緻性。
heap表的資料的更新會寫入相應的xlog,同時確定heap表資料頁的同步必須在對應的xlog同步完成後才能進行。
你可能有疑問:heap表的資料更新同步到mirror是個異步的過程,那麼會不會出現一個事務送出了,heap表資料更新還沒有來得及同步到mirror,這時候primary failover切換到mirror,導緻heap表資料丢失?當然不會的,雖然heap表資料同步是一個異步的過程,但是xlog的同步卻是一個強同步的過程。primary failover切換到mirror之後,mirror上面的xlog和primary的xlog完全一緻,這時候mirror會啟動startup程序,進入recovery模式,應用xlog,是以即便heap表資料沒有同步過來,mirror也會通過xlog将這些沒有過來的資料恢複。
其他檔案的更新,其實不需要實時同步。切換時mirror會回放xlog,恢複這些檔案的内容。
這樣,如果primary與mirror保持同步,上述順序保證了任何時間點mirror節點的資料都能達到一緻。但是,假如出現了網絡阻塞或者mirror當機的情況,資料就無法及時同步到mirror。此時,如果primary在更新資料時,等待資料被同步到mirror,就會被阻塞,而無法繼續提供服務。為解決這個問題,greenplum提供了異常處理機制。
此處所說的對網絡阻塞或mirror當機異常情況的處理,其實就是greenplum所謂的change tracking機制。在primary向mirror同步資料的時候,如果mirror長時間沒有回應primary,那麼primary将會認為mirror挂掉,這個時候master将會把系統表gp_segment_configuration裡面的mirror狀态(status)置為’d’,同時把primary的模式(mode)置為’c’,而這個’c’模式就是changetracing mode。primary進入change tracking狀态後,不會再試圖同步資料到mirror(每次有資料更改時會調用filerepprimary_ismirroringrequired進行檢查是否需要同步)。
primary進入changetracing mode之後,每次更新資料産生的xlog,會被立即解析成資料更新記錄,放入到change log檔案裡面(參見<code>changetracking_addrecordfromxlog</code>函數)。change log檔案在pg_changetracking/目錄下:
changetracing資訊具體記錄在ct_log_full檔案裡面,檔案記錄的核心資訊是目前的資料更新在xlog中的位置,檔案内容經過解析之後如下:
change log裡面隻存放heap表的修改資訊。ao表的更新資訊存放在特定的表中,無需另外記錄。而xlog和普通檔案,都完整儲存在primary的資料目錄下,無需記錄修改資訊(具體原因在異常恢複的說明中有介紹)。
change log其實是存放的heap表更改頁的中繼資料資訊,并未存放更改的實際内容。是以它并不占用太多存儲空間,另外它還可以對相同頁上的修改進行合并,進一步壓縮大小,減少恢複時間(參見<code>filerepprimary_runchangetrackingcompacting</code>函數)。
那麼,mirror在當機後重新開機或網絡擁塞發生後恢複正常了,重新連接配接到primary後,如何通過change log恢複同步呢?
異常恢複
在異常情況消失後,需要通過執行<code>gprecoverseg -a</code>指令來恢複同步。下面我們還是把資料分成4類來說明這個過程總資料同步恢複的過程。
heap表恢複
當我們執行<code>gprecoverseg -a</code>指令恢複mirror時,primary的resync程序通過change log資訊,再結合xlog,将積累的資料變更再次同步給mirror。
具體步驟如下:
resync manager程序通過調用一系列函數filerepresyncmanager_inresynctransition->persistentfilesysobj_markpageincrementalfromchangelog->persistentfilesysobj_markpageincremental->persistentfilesysobj_updatetuplepageincremental,将需要更新的page的資訊加入到resyncentry同步隊列中。
resync worker程序從resyncentry隊列中取出需要恢複到mirror的任務,通過調用一系列函數filerepprimary_resyncbufferpoolincrementalwrite->smgrwrite将page寫到緩沖區中,再通過上面的方法構造消息發送到mirror。
ao表恢複
因為ao表不寫xlog,是以change log中并沒有記錄ao表更新操作。那麼mirror是如何将ao表恢複到和primary資料一緻呢?其實在gp catalog中有一張gp_persistent_relation_node表,裡面記錄了ao表同步到mirror的最後一次檔案位置(mirror_append_only_loss_eof),以及目前檔案位置(mirror_append_only_loss_eof)。ao表檔案位置的更新是在finishpreparedtransaction函數完成的(執行commit prepared or rollback prepared)。最後resync worker程序将會把未同步到mirror的增量資料再次通過消息同步給它,最終達到primary和mirror的資料一緻性。
xlog檔案的恢複
我們知道,xlog檔案其實都儲存在primary的pg_xlog目錄下。在異常恢複時,把改目錄下的檔案直接發送到mirror即可。需要注意的是,異常期間是可以正常删除或規定xlog檔案的,這是因為,所有的heap表和ao表的修改都已經被儲存下來了,無需另外保留一份xlog來恢複資料。
其他檔案的恢複
其他檔案(pg_control, pg_clog, pg_mutitrans等檔案)也和xlog檔案一樣,在恢複時直接全部發送到mirror,具體參見<code>filerepresyncmanager_resyncflatfiles</code>函數。