multisite代碼中大量使用了Boost的協程,在了解協程的使用方法后,整體代碼結構還是比較清晰的。
協程實現
rgw中的協程庫使用的是boost庫,boost庫中corotuine實現原理是由基類保存函數當前執行位置,每次運行時根據switch判斷要執行的位置,具體可參考boost coroutine 實現原理記錄。
一次同步操作是由多個RGWCoroutine
實例完成,每個RGWCoroutine
作為一個基礎的op由一個RGWCoroutineStack
管理,一個stack內會有多個op,但只有最新加入的op能獲得執行機會,op執行完成后會被移除出stack隊列,進而stack中下一個op獲得執行機會。一個RGWCoroutineManager
實例分層管理多個stack集合,最新層stack集合中的每個stack都有同等運行機會,一次RGWCoroutineManger::run()
方法會新建一層stack集合,直到集合中的所有stack(即stack中的全部op)執行完畢后返回。一個op調用另一個op有兩種方式:call
和spawn
。call
方法在當前op隸屬的stack上加入新的op,直到新op執行完后才會繼續執行自己的代碼;spawn
方法會將新的op放到新建的stack中,新stack會被放到manager的當前層(最新層),從而兩個op能并發執行(由于stack是順序遍歷的,所以兩個op也是順序執行的)。
每個coroutine op都要實現自己的
operate()
方法,manager在遍歷stack list時會調用RGWCoroutine::operate()
,一般情況下operate()
方法結束時會調用set_cr_error()
或set_cr_done()
表示op已經完成,但對于RGWMetaSyncShardCR
等op,operate()
返回時并沒有設置完成標志,因此這個op會一直執行(重復被調用operate()
方法),其parent也會一直處于waiting_for_child狀態。
同步實現
multisite的功能是實現一個zone group內多個zone的數據同步。這里的數據被分成了兩類:
- meta data同步。包括bucket相關對象和user相關對象(user.uid namespace 下的uid信息和root namespace下的bucket以及bucket-instance信息),位于
.rgw.meta
pool中。元數據同步可以類比為手動在本地zone創建bucket和user。 - data同步。即每個bucket下的對象。data數據同步可以類比為手動在本地上傳/刪除bucket下的對象。
啟動rgw 實例時在RGWRados::initialize()
中會啟動相關的同步組件。對于meta data,每個rgw啟動一個單獨線程來執行同步,而對于data數據的同步,由于每個zone都需要向其他所有zone進行同步,因此會啟動n-1個同步線程,每個線程負責本地到另外一個zone的同步。
meta data的同步
目的: 將rgw.meta
pool下的bucket對象,bucket-instance對象以及uid對象拷貝到本地,且為每個bucket創建shard對象。
輔助結構:
.rgw.log pool
中的mdlog.sync-status
對象存儲本zone當前的元數據同步狀態。
.rgw.log pool
中的mdlog.sync-status.<shard>
對象存儲每個shard當前同步進度(用marker表示)。
.rgw.log pool
中的meta.full-sync.index.<shard>
對象用omap來存儲從master zone的.rgw.meta
pool拉取的數據(pool下的對象名, full-sync時使用)
.rgw.log pool
中的meta.log.<period>.<shardid>
對象用omap來存儲元數據操作log,比如創建bucket時,master zone的對象上會增加一條log記錄,slave zone從master zone來獲取這些記錄,從而得到需要從master拉取的數據的列表(bucket名字),然后對bucket元數據做同步。這種同步方式屬于incremental-sync。
代碼實現
data的同步
目的:將每個bucket下的對象拷貝到本地bucket下
輔助結構:
.rgw.log pool
中的datalog.sync-status.<zone>
對象存儲本zone到目標zone當前的數據同步狀態。
.rgw.log pool
中的datalog.sync-status.<zone>.<shard>
對象存儲本zone到目標zone當前的數據同步進度。
.rgw.log pool
中的data.full-sync.index.<zone>.<shard>
對象的omap用來存儲從目標zone的拉取的bucket-info信息
.rgw.log pool
中的data_log.<shard>
對象的omap中存放對象操作日志。當對bucket進行對象操作時,會在omap上新建一條"1_"+<timestamp> 開頭的日志,表明這個bucket被修改過,增量同步時會根據這些日志判斷出哪些bucket被更改過,進而再針對每個bucket進行同步。
.rgw.log pool
中的bucket.sync-status.<src-zone>:<[tenant/][bucket-name:][bucket-id:][bucket-shard]>使用xattr存放對應bucket的同步狀態
bucket shard對象omap中0x80+"0_"命名空間下的key記錄了此bucket的對象操作日志,用于增量同步時使用。
代碼實現:
注意:
當zone之間的sync 網絡不可用時,每個zone是可以本地操作上傳和刪除對象的。在網絡恢復后,各個zone最后存在的版本將是modify-time最新的那次上傳的版本。網絡故障期間如果有個別zone執行了del操作,即使操作時間是最新的,此次del操作最終會被其他put操作覆蓋掉。如果多個put操作的modify-time相同且文件內容不同,則按照short_zone_id
大小比較(代碼實現見obj_time_weight::operator<
)。