3.2.5 中繼資料/ 資料同步
CephRGW的多資料中心(Multisite)機制用于實作多個 Ceph 對象存儲叢集之間的中繼資料、資料同步。
1. 中繼資料同步
(1)多資料中心簡介
Ceph 的多資料中心有如下幾個概念:Realm、ZoneGroup、Zone,如圖 3-31所示。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SM5kTMldDO3MWOlZTYmRWOyMWY0QmMyEzYkZjMycTZw8CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)
圖 3-31 多資料中、示意
每個 Realm 都為一個獨立的命名空間,桶名在所在命名空間内是唯一的,即一旦在某個 Realm下建立了桶A,則 A這個名字就被使用了,在該 Realm 下其他人就無法建立出名字為A的桶。
一個 Realm下可以有多個 ZoneGroup。顧名思義,每個ZoneGroup可以對應多個Zone,即 ZoneGroup是一組 Zone的集合,Zone之間同步資料和中繼資料。
通常一個 Zone為多台伺服器組成的一個 Ceph叢集,由一組 RGW 對外提供服務,一個叢集上部署多個 RGW網關,以對請求進行負載均衡。
在一個 Realm下的多個 ZoneGroup中, 必須有一個 MasterZoneGroup,MasterZoneGroup中必須有一個 MasterZone,在 MasterZoneGroup下的 MasterZone中執行使用者的建立、删除、修改操作會記錄一些日志資訊(MDlog),這些日志資訊被克隆到其他 ZoneGroup下的 Zone中,其他Zone中的 RGW網關依照日志資訊從 MasterZoneGroup 下的 MasterZone 中已配置的 endpoints 拉取中繼資料資訊并執行相應操作。
在 Ceph的配置中有以下幾個參數與多資料中心機制相關,分别為 rgw_realm、rgw_zonegroup、rgw_zone。一旦設定好這 3 個參數并啟動 RGW網關,RGW就會預設到.rgw.root下尋找相應的 Realm、ZoneGroup、Zone 資訊,如果無法找到則啟動失敗。使用者也可以通過修改參數rgw_realm_root_pool、rgw_zonegroup_root_pool、rgw_zone_root_pool 的配置值,來告訴RGW網關到指定的存儲池下讀取 Realm、ZoneGroup、Zone 等資訊。預設情況下,一個Realm下的不同ZoneGroup之間隻會進行中繼資料同步,中繼資料包括
使用者資訊、bucket、bucket.instance資訊。RGW執行個體在啟動時,會啟動 RGWMetaSync-
ProcessorThread 線程進行多資料中心中繼資料的同步服務。
一個新的ZoneGroup加入已存在的Realm 時,會執行全量同步,完成全量同步後就會進入增量同步階段。在此階段,新加入的 ZoneGroup下的Zone内的 RGW網關每隔 20s
(通過 INCREMENTAL_INTERVAL參數配置)到 MasterZoneGroup中拉取日志資訊MDlog。在增量同步階段,每隔 20s執行如下動作。
1) 查詢請求帶上 marker參數發送到MasterZoneGroup,查詢是否有新增的MDlog,如果有,則拉取新增的MDlog到本地叢集;
2) 讀取儲存在本叢集的新增的 MDlog并處理,按照 MDlog記錄資訊發送讀取中繼資料請求到 MasterZoneGroup;
3)儲存從 MasterZoneGroup 讀取到的中繼資料資訊到本地叢集;4)更新 marker參數。
(2) MDLog簡介
Mdlog為 MasterZoneGroup上的RGW網關記錄, 日志資訊記錄在 Log池下的meta.log.PERIOD.SHARD_ID對象的 OMAP上,shard_id預設為 0~31。
以下指令可查詢第 0個 shard上的 omapkey,key為 1_開頭,後面帶記錄 Log的時間戳。
#rados -p zgp2-z1.rgw.log listomapkeys meta.log.315d0473-9ff8-4828-83fd-96fdc36ed618.01_1598684563.695864_0.1
也可以使用radosgw-admin指令檢視MDlog日志資訊的狀态,狀态資訊中有marker和 last_update的時間資訊,marker記錄上次同步的位置,last_update記錄上次同步的時間。
#radosgw-admin mdlog status[
{
"marker": "1_1598768113.971442_11.1""last_update":"2020-08-3006:15:13.971442Z"
}
]
status資訊儲存在 Log池下的 RADOS 對象中,可通過如下指令進行查詢。
#rados -p zgp2-z1.rgw.log lsmdlog.sync-status.shard.0mdlog.sync-status
當主資料中心沒有中繼資料更新記錄到MDlog時,以下是從主資料中心拉取 MDlog請求時沒有新 MDlog傳回的請求和響應。
GET/admin/log?type=metadata&id=0&period=315d0473-9ff8-4828-83fd-
96fdc36ed618&max-entries=100&marker=目前的 marker&rgwx-zonegroup=7085627f-27f8-
4779-9552-ebdd13c265e2HTTP/1.1
HTTP/1.1200 OK
Content-Length:44
"marker":""
"entries": []"truncated":false
當主資料中心有中繼資料更新記錄到MDlog時,以下是從主資料中心拉取 MDlog請求時有新 MDlog傳回的請求和響應。
96fdc36ed618&max-entries=100&marker= 目前的marker&rgwx-zonegroup=7085627f-27f8-
Content-Length:598
"marker":"1_1598774754.303770_13.1"
"entries":[
...
"timestamp":"2020-08-3008:05:54.234410256Z"
"section":"user"
"data": {
"status": {
"status":"write"
如果從主資料中心拉取 MDlog請求時有新的 MDlog傳回,發起拉取請求的 RGW則進入 MDlog的處理流程,即發送新的擷取中繼資料請求到 MasterZoneGroup去拉取新的資訊覆寫本地舊的中繼資料資訊。如下為在MasterZoneGroup中建立一個使用者後,非MasterZoneGroup向 MasterZoneGroup的網關發起的拉取使用者資訊的請求。
GET/admin/metadata/user/user001?key=user001&rgwx-zonegroup=abcHTTP/1.1
Content-Length:713
"default_storage_class": """keys": [
"access_key":""
"secret_key":""
"user":"user001"
拉取到新的使用者資訊寫入本地叢集後,更新marker參數,這樣在下一個20s時帶上該 Marker參數,就會隻傳回本Zone沒有的 MDlog,對處理過的 MDlog就不會傳回,進而實作了中繼資料的增量更新。
RGW 程序隻有同時滿足如下條件,才會進行MDlog的記錄。
◆ rgw_zonegroup為 MasterZoneGroup。
◆ 目前的ZoneGroup内的Zone個數多于1個或者目前Realm下的ZoneGroup多于1個。
(3) 示例:非主資料中心建立桶
使用者資訊在 MasterZoneGroup中建立後通過MDlog的方式同步到其他 ZoneGroup下所有的 Zone中,例如非 MasterZoneGroup下的某個RGW 網關接收到建立桶的請求,該 RGW網關會将請求轉發到 MasterZoneGroup的網關處理。
voidRGWCreateBucket::execute()
if (!store->svc.zone->is_meta_master()) {JSONParserjp;
op_ret=forward_request_to_master(s NULLstore in_data&jp);
如果主資料中心建立失敗(例如主資料中心沒有該使用者,該使用者在非MasterZoneGroup中建立),則建立桶失敗。是以所有使用者必須在MasterZoneGroup中建立,并通過 MDlog同步到其他資料中心,使用者的修改和删除也必須在 MasterZoneGroup中執行。如果 MasterZoneGroup成功傳回轉發建立桶的請求,則繼續執行剩餘的建立桶流程,将 bucketinfo儲存到本資料中心的RADOS。MasterZoneGroup接收到該建立桶的請求後,其下的RGW也會執行 RGWCreateBucket::execute()。由于它是主資料中心,同時也會記錄 MDlog,在中繼資料同步線程中 MDlog會克隆到其他ZoneGroup,所有的ZoneGroup下都會儲存該 bucketinfo資訊,例如 MasterZoneGroup為 beijing1,建立桶的請求發到ZoneGroup為beijing2的 RGW網關,這個請求會被beijing2 的RGW網關轉發到 beijng1的RGW網關,同時 MDlog資訊會被同步到beijing2、guangzhou1、hunan1等所有 ZoneGroup。在建立好桶之後,如果向這個桶上傳資料,則需要将上傳資料請求發到ZoneGroup為beijing2的 RGW網關。如果上傳請求發到ZoneGroup 為guangzhou1的 RGW網關,guangzhou1的 RGW網關會傳回301 狀态碼,表明請求所通路的桶不在本資料中心。
對于其他桶的中繼資料操作,大部分的請求會被轉發到MasterZoneGroup,例如删除桶、設定桶的靜态網站、設定桶的多版本控制、設定桶的桶政策、設定桶的 ACL、設定桶的生命周期規則、設定桶的跨域通路配置等。
2. 資料同步
Ceph 的資料同步是指在多資料中心不同Zone 之間同步使用者上傳的檔案資料。
可以将實體資料的同步分為 3 個部分:記錄日志、資料更新通知以及資料更新。下面分别介紹。
(1)記錄日志
在對資料進行操作時(比如上傳、删除等操作),RGW會記錄一些日志資訊,為之後的實體資料同步服務。日志主要分兩部分。
◆ bucketindexlog:在更新 bucketindex、設定 olh(objectlogicalhead,對象邏輯頭)時會記錄該日志,包含了對象、操作類型等資訊;
◆ datalog:記錄發生變化的 bucketshard 等資訊。
在進行同步時,依據 datalog,可以知道哪些 bucketshard 發生了資料的變化。而通過bucketindexlog,則可以對對應的對象進行操作。比如,indexlog中記錄的是add操作,就會從 SourceZone 擷取具體的對象,如果是 remove 操作,就會把相應的對象删除。
(2)資料更新通知
與中繼資料同步類似,實體資料的同步同樣擁有一個線程周期性地進行資料更新通知。
◆ 初始化
實體資料的更新通知由 RGWDataNotifier線程負責。它的初始化以及啟動都是在RGWRados的初始化函數中。
data_notifier = new RGWDataNotifier(this);data_notifier->start();
◆ 運作
在被啟動之後,每隔一段時間(由 rgw_md_notify_interval_msec配置,預設 200ms)
會進行資料更新通知,将記錄在datalog中發生變化的 shard發送到其他 Zone。其他Zone在接收到更新通知後,會喚醒相應的資料同步線程。
(3)資料更新
為了與不同的 Zone進行實體資料的同步,RGW 會啟動單獨的同步線程。
資料同步線程的初始化,同樣在 RGW 的初始化中,資料同步線程可能會有多個。對于需要進行資料同步的Zone,都會啟動一個線程來專門負責從該Zone 擷取同步資料。
同步線程啟動之後,會開始調用 RGWDataSyncProcessorThread的 process來對資料進行處理,其主要流程如下。
1) 從 RADOS中讀取 datasyncstatus,以及各個 Logshard的 syncmarker。如果是第一次同步,RADOS 中還不存在這些資訊,會先對 status 進行初始化。
2) datasyncstatus共 有 3種 狀 态, 即 StateInit、StateBuildingFullSyncMaps、StateSync。依據狀态的不同,會執行不同的操作。
a)StateInit:該狀态下,會執行一些同步的初始化操作,例如,往LogPool 中寫入sync_status對象,從遠端擷取各個 Logshard的 syncmarker寫入LogPool,将 sync_status設定為 StateBuildingFullSyncMaps等。
b)StateBuildingFullSyncMaps:該狀态下,會從遠端擷取所有的 bucket 資訊。之後,會以 bucket shard為機關,将所有需要同步的bucketshard寫入 OMAP中,并更新 Logshard的同步 marker,最後将狀态置為StateSync。
c)StateSync:該狀态即為正常的同步狀态,在進行同步時,以 Logshard為機關,對每一個 Logshard進行資料同步操作。
3) 在對某個 Logshard進行資料同步時,依據Logshard的 syncmarker來判斷執行全量還是增量同步。同樣,在執行過一次全量同步後,之後執行的就是增量同步了。
4) 在每一個 Logshard中,包含了多個條目,每一個條目是一個bucketshard資訊。對 Logshard的同步,實際上就是周遊并同步這些bucketshard。
5) 同步 bucketshard過程中有不同的狀态。依據不同的狀态,來依次執行初始化、全量同步以及增量同步。同樣,初始化與全量同步隻會執行一次,之後便是增量同步。為 了同步 bucketshard,RGW會從對端Zone的RGW擷取該bucketshard的bucketindexlog,并依據這些 Log,最終決定是從遠端擷取實體對象,還是從本地删除對象,或者進行其他的操作,此時才會涉及真正的實體資料的操作。
(4)删除日志
如果不删除日志,則随着時間的增加,日志會越來越大。是以,RGW每隔一段時間都會删除已經同步完成的資料日志。間隔時間由rgw_sync_log_trim_interval确定,預設是1200s。在進行日志删除時,需要從各個 Zone擷取資料同步狀态資訊,并根據這些資訊, 判斷出哪些日志已經被同步完成了,并将其從RADOS中删除。
(5)總結
從實體資料同步過程中可以看到涉及多種同步狀态的判斷。之是以有這麼多的狀态, 是因為 RGW 在進行資料同步時,将其在邏輯上分成了多個層級。我們可以将同步的層級分成如下4個層次。
1)Zone級别
該層級表示了與某個 Zone 的同步狀态,表征該層級的同步狀态由下面的結構給出。
struct rgw_data_sync_info {enum SyncState {StateInit = 0
StateBuildingFullSyncMaps=1
StateSync = 2
};
uint16_t state;uint32_tnum_shards;
rgw_data_sync_info():state((int)StateInit)num_shards(0){}
2)Logshard級别
記錄資料變化時會将日志分成多個 Log,進而在資料量較大時,獲得較好的性能。下面是表示 Logshard層級的同步狀态結構。
struct rgw_data_sync_marker {enum SyncState {
FullSync = 0
IncrementalSync= 1
uint16_t state;stringmarker;
string next_step_marker;uint64_t total_entries;uint64_tpos;
real_timetimestamp;
rgw_data_sync_marker():state(FullSync)total_entries(0)pos(0){}
3)bucketshard級别
預設情況下,bucketshard大小為 0。但為了讓單個容器可以承載更多的對象,不得不以犧牲 list對象的性能為代價,增大bucketshard的值。目前線上上環境中,該值通常都不配置為 0。是以,我們可以認為,每個bucket實際上都存在多個 shard,各自承載着部分對象。而在同步過程中,每一個 bucketshard都歸屬于某個 Logshard。對于logshard的同步,實際上就是對其下的各個 bucketshard進行同步。
4)對象級别
在每一個 bucketshard中都儲存了很多對象, 同步 bucketshard,就是同步其下面的這些對象。該層級涉及對實體資料的操作,并且也是同步過程中的最底層(不考慮RADOS),沒有專門的結構來儲存同步資訊。
3. 小結
因為 Multisite是一個Zone層面的功能處理機制,是以預設情況下是 Zone級的資料同步,即配置了Multisite之後,整個 Zone中的資料都會被同步處理。
整個Zone 層面的資料同步,操作粒度過于粗糙,在很多場景下都是非常不适用的。目前,CephRGW還支援通過bucketsyncenable/disable來啟用/禁用存儲桶級的資料同步,操作粒度更細,靈活度也更高。