天天看點

Mongodump的archive(歸檔)模式原了解析

mongodump是mongodb官方的邏輯備份工具,本文将介紹其archive(歸檔)模式的相關原理。

使用archive輸出的話,mongodump會将各個集合的資料進行一個混合,最後輸出到一個檔案裡。這樣有兩個好處:

友善進行網絡傳輸。

友善和其他工具配合使用如直接作為mongorestore的輸入。

mongodump的archive模式的實作支援多個集合并發進行dump,通常來說要實作并發就很難做到輸出到一個檔案中,我們來看下它是怎麼做的。

mongodump使用go寫的,是以大量使用了goroutine。主要需要關注兩類goroutine,一類是dump資料的(可指定并行度即goroutine個數)backup goroutine,還有一個則是混合各集合資料并真正輸出到歸檔檔案的multiplexer goroutine。如下圖所示:

Mongodump的archive(歸檔)模式原了解析
Mongodump的archive(歸檔)模式原了解析

當multiplexer goroutine啟動後就不停的執行select(),當它從control channel收到muxin資料結構時,就會将其中的writechan添加到select的channel中,并将這個muxin儲存在自己的數組中。然後下一輪循環就會開始監聽control channel和這個writechan。

每個backup goroutine開始幹活時,它一邊從mongodb dump資料,一邊将資料通過writechan發送給multiplexer goroutine。這是一個典型的生産者消費者模型,為了不讓消費者的磁盤i/o影響到生産者(從mongodb讀資料),它又起了一個dump goroutine,通過一個buffchan來傳輸資料,順便在這個goroutine中處理退出信号(主goroutine起了一個信号處理goroutine用于捕獲sigterm、sigint和sighup,再通過一個termchan和其他goroutine通信),當接收到退出信号時,關閉buffchan并退出。

Mongodump的archive(歸檔)模式原了解析

backup goroutine的buf收滿之後,就将資料通過writechan發送給multiplexer goroutine,并等待從writelenchan接收資料,如果傳回的寫成功的資料長度和buf的資料長度不一緻 ,則傳回失敗。

multiplexer goroutine從writechan收到資料,将資料寫入歸檔檔案。由于同時可能有多個backup goroutine在工作,是以需要對資料進行混合。這裡主要是按集合進行分條(slice)處理,每個條有一個header、body和一個terminator。header就是集合的namespace(db和集合名),body是集合的資料,terminator是一個4位元組的結束标記。另外每個集合的最後一條之後還有一個标明集合結束的eof條。multiplexer goroutine會維護一個目前正在處理的集合名,如果發生集合資料交叉,會結束目前條(寫入一個terminator),然後另起一個新的條(寫入一個新的header)。寫完資料後,會将這次寫成功的資料通過writelenchan發送給backup goroutine。歸檔檔案的實體格式如下圖所示:

Mongodump的archive(歸檔)模式原了解析

backup goroutine針對某個集合dump結束時,會依次關閉writechan、writelenchan,然後等待從writeclosefinishedchan接收資料。multiplexer goroutine感覺到writechan關閉時,發送資料給writeclosefinishedchan,然後往目前條寫入條結束标記以及eof條。這裡之是以要有一個writeclosefinishedchan是為了避免multiplexer goroutine的control channel比writechan先關閉。如果control channel關閉了,那就會結束整個dump過程。backup goroutine從writeclosefinishedchan接收到資料傳回後又可以處理下一個集合,直到所有集合處理完畢。

主goroutine在建立backup goroutine時會建立一個resultchan。當backup goroutine發現所有集合都dump完畢時,或者在dump過程中遇到錯誤時,都會往resultchan發送資料并退出。當主goroutine從resultchan接收到每個backup goroutine發送的資料時,或者收到某個backup goroutine發送的錯誤,就會傳回。當主goroutine幹完所有事情傳回時,它會關閉multiplexer goroutine的control channel,這樣multiplexer goroutine就可以退出了。

mongodump通過這種架構實作了輸出到一個歸檔檔案兼顧支援并發的需求,可以作為一個參考。

<a href="https://engineering.mongodb.com/post/multiplexing-golang-channels-to-maximize-throughput/">multiplexing golang channels to maximize throughput</a>