日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【ceph】Ceph 存储中 PGMap、OSDMap 和xxMap

發(fā)布時(shí)間:2024/3/12 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【ceph】Ceph 存储中 PGMap、OSDMap 和xxMap 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

簡(jiǎn)介

OSDMap

PG 和 PGMap

OSDMap 機(jī)制淺析

OSDMap 代碼淺析

二、OSDMap模塊數(shù)據(jù)結(jié)構(gòu)

1.osd_info_t

2.osd_xinfo_t

3.OSDMap

4.Incremental

三、MOSDMap消息

四、OSDMap更新機(jī)制

五、OSDMap要點(diǎn)分析

六、獲取OSDMap

1.查看當(dāng)前集群最新epoch的OSDMap信息

七、與OSDMap相關(guān)的參數(shù)配置

八、疑點(diǎn)


作者bandaoyu,隨時(shí)更新本文鏈接:https://blog.csdn.net/bandaoyu/article/details/123097837

本文主要介紹ceph分布式存儲(chǔ)架構(gòu)中OSDMap和PGMap的原理及相關(guān)重要信息。

什么是OSDMap 和 PGMap

(摘自:https://blog.51cto.com/wendashuai/2511361,源文:Analizar Ceph: OSD, OSDMap y PG, PGMap - programador clic)

Monitor 作為Ceph的 Metada Server 維護(hù)了集群的信息,它包括了6個(gè) Map,分別是 MONMap,OSDMap,PGMap,LogMap,AuthMap,MDSMap。其中 PGMap 和 OSDMap 是最重要的兩張Map,本文會(huì)重點(diǎn)介紹。

OSDMap


????????OSDMap 是 Ceph 集群中所有 OSD 的信息,所有 OSD 狀態(tài)的改變?nèi)邕M(jìn)程退出,OSD的加入和退出或者OSD的權(quán)重的變化都會(huì)反映到這張 Map 上。這張 Map 不僅會(huì)被 Monitor 掌握,OSD 節(jié)點(diǎn)和 Client 也會(huì)從 Monitor 得到這張表,因此實(shí)際上我們需要處理所有 “Client” (包括 OSD,Monitor 和 Client)的 OSDMap 持有情況。


????????實(shí)際上,每個(gè) “Client” 可能會(huì)具有不同版本的 OSDMap,當(dāng) Monitor 所掌握的權(quán)威 OSDMap 發(fā)生變化時(shí),它并不會(huì)發(fā)送 OSDMap 給所有 “Client” ,而是需要那些感知到集群變化的 “Client” 會(huì)被 Push,比如一個(gè)新的 OSD 加入集群會(huì)導(dǎo)致一些 PG 的遷移,那么這些 PG 的 OSD 會(huì)得到通知。除此之外,Monitor 也會(huì)隨機(jī)的挑選一些 OSD 發(fā)送 OSDMap。


????????那么如何讓 OSDMap 慢慢傳播呢?


????????比如 OSD.a, OSD.b得到了新的 OSDMap,那么 OSD.c 和 OSD.d 可能部分 PG 也會(huì)在 OSD.a, OSD.b 上,這時(shí)它們的通信就會(huì)附帶上 OSDMap 的 epoch,如果版本較低,OSD.c 和 OSD.d 會(huì)主動(dòng)向 Monitor pull OSDMap,而部分情況 OSD.a, OSD.b 也會(huì)主動(dòng)向 OSD.c 和 OSD.d push 自己的 OSDMap (如果更新)。因此,OSDMap 會(huì)在接下來一段時(shí)間內(nèi)慢慢在節(jié)點(diǎn)間普及。在集群空閑時(shí),很有可能需要更長的時(shí)間完成新 Map的更新,但是這并不會(huì)影響 OSD 之間的狀態(tài)一致性,因?yàn)镺SD沒有得到新的Map,所以它們不需要知曉新的OSDMap變更。

????????Ceph 通過管理多個(gè)版本的 OSDMap 來避免集群狀態(tài)的同步,這使得 Ceph 絲毫不會(huì)畏懼在數(shù)千個(gè) OSD 規(guī)模的節(jié)點(diǎn)變更,而導(dǎo)致集群可能出現(xiàn)的狀態(tài)同步的問題。

新OSD啟動(dòng)OSDMap的變化

??????????當(dāng)一個(gè)新的 OSD 啟動(dòng)時(shí),這時(shí) Monitor 的最新 OSDMap 并沒有該 OSD 的情況,因此該 OSD 會(huì)向 Monitor 申請(qǐng)加入,Monitor 在驗(yàn)證其信息后會(huì)將其加入 OSDMap 并標(biāo)記為IN,并且將其放在 Pending Proposal 中會(huì)在下一次 Monitor “討論”中提出,OSD 在得到 Monitor 的回復(fù)信息后發(fā)現(xiàn)自己仍然沒在 OSDMap 中會(huì)繼續(xù)嘗試申請(qǐng)加入,接下來 Monitor 會(huì)發(fā)起一個(gè) Proposal ,申請(qǐng)將這個(gè) OSD 加入 OSDMap 并且標(biāo)記為 UP 。然后按照 Paxos 的流程,從 proposal->accept->commit 到最后達(dá)成一致,OSD 最后成功加入 OSDMap 。當(dāng)新的 OSD 獲得最新 OSDMap 發(fā)現(xiàn)它已經(jīng)在其中時(shí)。這時(shí),OSD 才真正開始建立與其他OSD的連接,Monitor 接下來會(huì)開始給他分配PG。

OSD crash

?
圖C: OSD down過程

????????當(dāng)一個(gè) OSD 因?yàn)橐馔?crash 時(shí),其他與該 OSD 保持 Heartbeat 的 OSD 都會(huì)發(fā)現(xiàn)該 OSD 無法連接,在匯報(bào)給 Monitor 后,該 OSD 會(huì)被臨時(shí)性標(biāo)記為 OUT,所有位于該 OSD 上的 Primary PG 都會(huì)將 Primary 角色交給其他 OSD(下面會(huì)解釋)。

PG 和 PGMap

?圖D: PG和PGMap

????????PG(Placement Group)是 Ceph 中非常重要的概念,它可以看成是一致性哈希中的虛擬節(jié)點(diǎn),維護(hù)了一部分?jǐn)?shù)據(jù)并且是數(shù)據(jù)遷移和改變的最小單位。它在 Ceph 中承擔(dān)著非常重要的角色,在一個(gè) Pool 中存在一定數(shù)量的 PG (可動(dòng)態(tài)增減),這些 PG 會(huì)被分布在多個(gè) OSD ,分布規(guī)則可以通過 CRUSH RULE 來定義。


????????Monitor 維護(hù)了每個(gè)Pool中的所有 PG 信息,比如當(dāng)副本數(shù)是三時(shí),這個(gè) PG 會(huì)分布在3個(gè) OSD 中,其中有一個(gè) OSD 角色會(huì)是 Primary ,另外兩個(gè) OSD 的角色會(huì)是 Replicated。Primary PG負(fù)責(zé)該 PG 的對(duì)象寫操作,讀操作可以從 Replicated PG獲得。而 OSD 則只是 PG 的載體,每個(gè) OSD 都會(huì)有一部分 PG 角色是 Primary,另一部分是 Replicated,當(dāng) OSD 發(fā)生故障時(shí)(意外 crash 或者存儲(chǔ)設(shè)備損壞),Monitor 會(huì)將該 OSD 上的所有角色為 Primary 的 PG 的 Replicated 角色的 OSD 提升為 Primary PG,這個(gè) OSD 所有的 PG 都會(huì)處于 Degraded 狀態(tài)。然后等待管理員的下一步?jīng)Q策,所有的 Replicated 如果原來的 OSD 無法啟動(dòng), OSD 會(huì)被踢出集群,這些 PG 會(huì)被 Monitor 根據(jù) OSD 的情況分配到新的 OSD 上。

PG的peering過程

圖E: PG的peering過程

????????在 Ceph 中,PG 存在多達(dá)十多種狀態(tài)和數(shù)十種事件的狀態(tài)機(jī)去處理 PG 可能面臨的異常, Monitor 掌握了整個(gè)集群的 OSD 狀態(tài)和 PG 狀態(tài),每個(gè)PG都是一部分 Object 的擁有者,維護(hù) Object 的信息也每個(gè) PG 的責(zé)任,Monitor 不會(huì)掌握 Object Level 的信息。因此每個(gè)PG都需要維護(hù) PG 的狀態(tài)來保證 Object 的一致性。但是每個(gè) PG 的數(shù)據(jù)和相關(guān)故障恢復(fù)、遷移所必須的記錄都是由每個(gè) PG 自己維護(hù),也就是存在于每個(gè) PG 所在的 OSD 上。

???????????PGMap 是由 Monitor 維護(hù)的所有 PG 的狀態(tài),每個(gè) OSD 都會(huì)掌握自己所擁有的 PG 狀態(tài),PG 遷移需要 Monitor 作出決定然后反映到 PGMap 上,相關(guān) OSD 會(huì)得到通知去改變其 PG 狀態(tài)。在一個(gè)新的 OSD 啟動(dòng)并加入 OSDMap 后,Monitor 會(huì)通知這個(gè)OSD需要?jiǎng)?chuàng)建和維護(hù)的 PG ,當(dāng)存在多個(gè)副本時(shí),PG 的 Primary OSD 會(huì)主動(dòng)與 Replicated 角色的 PG 通信并且溝通 PG 的狀態(tài),其中包括 PG 的最近歷史記錄。通常來說,新的 OSD 會(huì)得到其他 PG 的全部數(shù)據(jù)然后逐漸達(dá)成一致,或者 OSD 已經(jīng)存在該 PG 信息,那么 Primary PG 會(huì)比較該 PG 的歷史記錄然后達(dá)成 PG 的信息的一致。這個(gè)過程稱為 Peering ,它是一個(gè)由 Primary PG OSD 發(fā)起的“討論”,多個(gè)同樣掌握這個(gè) PG 的 OSD 相互之間比較 PG 信息和歷史來最終協(xié)商達(dá)成一致。

OSDMap 機(jī)制淺析

(摘自:https://cloud.tencent.com/developer/article/1664568)

????????OSDMap 機(jī)制是 Ceph 架構(gòu)中非常重要的部分,PG 在 OSD 上的分布和監(jiān)控由 OSDMap 機(jī)制執(zhí)行。OSDMap 機(jī)制和 CRUSH 算法一起構(gòu)成了 Ceph 分布式架構(gòu)的基石。

OSDMap 機(jī)制主要包括如下3個(gè)方面:

1、Monitor 監(jiān)控 OSDMap 數(shù)據(jù),包括 Pool 集合,副本數(shù),PG 數(shù)量,OSD 集合和 OSD 狀態(tài)。

2、OSD 向 Monitor 匯報(bào)自身狀態(tài),以及監(jiān)控和匯報(bào) Peer OSD 的狀態(tài)。

3、OSD 監(jiān)控分配到其上的 PG , 包括新建 PG , 遷移 PG , 刪除 PG 。

????????在整個(gè) OSDMap 機(jī)制中,OSD充分信任 Monitor, 認(rèn)為其維護(hù)的 OSDMap 數(shù)據(jù)絕對(duì)正確,OSD 對(duì) PG 采取的所有動(dòng)作都基于 OSDMap 數(shù)據(jù),也就是說 Monitor 指揮 OSD 如何進(jìn)行 PG 分布。

????????在 OSDMap 數(shù)據(jù)中 Pool 集合,副本數(shù),PG 數(shù)量,OSD 集合這 4 項(xiàng)由運(yùn)維人員來指定,雖然 OSD 的狀態(tài)也可以由運(yùn)維人員進(jìn)行更改,但是實(shí)際運(yùn)行的 Ceph 集群 A 中,從時(shí)間分布來看,運(yùn)維人員對(duì) Ceph 集群進(jìn)行介入的時(shí)間占比很小,因此 OSD 的故障(OSD 狀態(tài))才是 Monitor 監(jiān)控的主要目標(biāo)。

????????OSD 故障監(jiān)控由 Monitor 和 OSD 共同完成,在 Monitor 端,通過名為 OSDMonitor 的 PaxosService 線程實(shí)時(shí)的監(jiān)控 OSD 發(fā)來的匯報(bào)數(shù)據(jù)(當(dāng)然,也監(jiān)控運(yùn)維人員對(duì) OSDMap 數(shù)據(jù)進(jìn)行的操作)。在 OSD 端,運(yùn)行一個(gè) Tick 線程,一方面周期性的向 Monitor 匯報(bào)自身狀態(tài);另外一方面,OSD 針對(duì) Peer OSD 進(jìn)行 Heartbeat 監(jiān)控,如果發(fā)現(xiàn) Peer OSD 故障,及時(shí)向 Monitor 進(jìn)行反饋。具體的 OSD 故障監(jiān)控細(xì)節(jié)本文不做分析。

OSDMap 機(jī)制中的第1點(diǎn)和第2點(diǎn)比較容易理解,下面本文主要針對(duì)第3點(diǎn)進(jìn)行詳細(xì)分析。

如上圖所示,在3個(gè) OSD 的 Ceph 集群中,Pool 的副本數(shù)為3,某個(gè) PG 的 Primary OSD 為 OSD0, 當(dāng) Monitor 檢測(cè)到 3 個(gè) OSD 中的任何一個(gè) OSD 故障,則發(fā)送最新的 OSDMap 數(shù)據(jù)到剩余的 2 個(gè) OSD 上,通知其進(jìn)行相應(yīng)的處理。

如上圖所示,OSD 收到 MOSDMap 后,主要進(jìn)行3個(gè)方面的處理

  • ObjectStore::Transaction::write(coll_t::meta()) 更新 OSDMap 到磁盤,保存在目錄 /var/lib/ceph/OSD/ceph-<id>/current/meta/,將 OSDMap 數(shù)據(jù)持久化,起到類似于 log 的作用。
  • OSD::consume_map() 進(jìn)行 PG 處理,包括刪除 Pool 不存在的 PG; 更新 PG epoch(OSDmap epoch) 到磁盤(LevelDB); 產(chǎn)生 AdvMap 和 ActMap 事件,觸發(fā) PG 的狀態(tài)機(jī) state_machine 進(jìn)行狀態(tài)更新。
  • OSD::activate_map() 根據(jù)需要決定是否啟動(dòng) recovery_tp 線程池進(jìn)行 PG 恢復(fù)。

在OSD端,PG 負(fù)責(zé) I/O 的處理,因此 PG 的狀態(tài)直接影響著 I/O,而 pgstate_machine 就是 PG 狀態(tài)的控制機(jī)制,但里面的狀態(tài)轉(zhuǎn)換十分的復(fù)雜,這里不做具體分析。

下面開始分析 PG 的創(chuàng)建,刪除,遷移

PG 的創(chuàng)建由運(yùn)維人員觸發(fā),在新建 Pool 時(shí)指定 PG 的數(shù)量,或增加已有的 Pool 的 PG 數(shù)量,這時(shí) OSDMonitor 監(jiān)控到 OSDMap 發(fā)生變化,發(fā)送最新的 MOSDMap 到所有的 OSD。

在 PG 對(duì)應(yīng)的一組 OSD 上,OSD::handle_pg_create() 函數(shù)在磁盤上創(chuàng)建 PG 目錄,寫入 PG 的元數(shù)據(jù),更新 Heartbeat Peers 等操作。

PG 的刪除同樣由運(yùn)維人員觸發(fā),OSDMonitor 發(fā)送 MOSDMap 到 OSD, 在 PG 對(duì)應(yīng)的一組 OSD 上,OSD::handle_PG _remove() 函數(shù)負(fù)責(zé)從磁盤上刪除PG 所在的目錄,并從 PGMap 中刪除 PG ,刪除 PG 的元數(shù)據(jù)等操作。

PG 遷移較為復(fù)雜,涉及到兩個(gè)OSD與monitor的協(xié)同處理。例如,向已有3個(gè)OSD的集群中新加入OSD3,導(dǎo)致 CRUSH 重新分布 PG , 某個(gè) PG 的分配變化結(jié)果為 [0, 1, 2 ] -> [3, 1, 2]。當(dāng)然,CRUSH 的分配具有隨機(jī)性,不同的 PG 中,OSD3 既可能成為 Primary OSD,也可能成為 Replicate OSD, 這里取 OSD3 作為 Primary OSD為例。

新加入的OSD3取代了原有的 OSD0 成為 Primary OSD, 由于 OSD3 上未創(chuàng)建 PG , 不存在數(shù)據(jù),那么 PG 上的 I/O 無法進(jìn)行,因此,這里引入 PG Temp 機(jī)制,即 OSD3 向 Monitor 發(fā)送 MOSDPG Temp,把 Primary OSD 指定為OSD1, 因?yàn)?OSD1 上保存了 PG 的數(shù)據(jù),Client 發(fā)送到 PG 的請(qǐng)求都被轉(zhuǎn)發(fā)到了 OSD1;與此同時(shí),OSD1 向 OSD3 發(fā)送 PG 的數(shù)據(jù),直到 PG 數(shù)據(jù)復(fù)制完成,OSD1 將 Primary OSD 的角色交還給 OSD3,Client 的 I/O 請(qǐng)求直接發(fā)送的 OSD3,這樣就完成了 PG 的遷移。整個(gè)過程如下圖所示。

另外一種 PG 的遷移情景是 OSD3 作為 Replicate OSD 時(shí),由 Primay OSD 向 OSD3 進(jìn)行 PG 數(shù)據(jù)遷移,比上述 PG 遷移過程更為簡(jiǎn)單,這里不再詳述。

本文從 PG 的視角闡述了 OSDMap 機(jī)制的基本原理,描述了 Monitor, OSD, PG 三者之間的關(guān)聯(lián)。 在實(shí)際運(yùn)維中,我們常常對(duì)于 OSD 狀態(tài)和數(shù)量的變化引起的 PG 狀態(tài)的變化感到疑惑,希望本文能夠?qū)鉀Q的 PG 狀態(tài)問題帶來啟發(fā)。

OSDMap 代碼淺析

(摘自:https://gitee.com/wanghongxu/cephknowledge/blob/master/Ceph-OSDMap.md)

一、OSDMap模塊簡(jiǎn)介

OSDMap是關(guān)于Ceph集群中所有OSD的信息,所有OSD節(jié)點(diǎn)的改變,踢出或加入集群,節(jié)點(diǎn)的權(quán)重改變都會(huì) 反映到這個(gè)Map上面。在Ceph集群中,所有的Server(MDS,MON和OSD...)和Client都得掌握這個(gè) Map。

每個(gè)角色都可能持有不同epoch的OSDMap,如果客戶端持有的map是過期的,可以利用OSD的回復(fù)來判斷。

二、OSDMap模塊數(shù)據(jù)結(jié)構(gòu)

1.osd_info_t

struct osd_info_t {epoch_t last_clean_begin;epoch_t last_clean_end;epoch_t up_from; // epoch osd marked upepoch_t up_thru; // lower bound on actual osd death (if > up_from)epoch_t down_at; // upper bound on actual osd death (if > up_from)epoch_t lost_at; // last epoch we decided data was "lost" ... };
  • last_clean_begin和last_clean_end: 以一個(gè)clean的osd關(guān)閉而結(jié)束的最終區(qū)間

  • up_from: osd被標(biāo)記為up時(shí)的epoch

  • up_thru: 實(shí)際osd終止時(shí)的下界(如果它大于up_from)

  • down_at: 實(shí)際osd終止時(shí)的上界(如果它大于up_from)

  • lost_at: 決定數(shù)據(jù)已經(jīng)丟失時(shí)的最終epoch

osd_info_t結(jié)構(gòu)用來表述隨著時(shí)間推移,各個(gè)狀態(tài)的epoch。

我們跟蹤在OSD存活且Clean時(shí)候的兩個(gè)區(qū)間,最新的是[up_from,up_thru]。up_thru是已知OSD已經(jīng) 啟動(dòng)的最后的epoch,即實(shí)際osd死亡的下界,down_at(如果它大于up_from)是實(shí)際osd死亡的上界。 第二個(gè)是last_clean區(qū)間[first,last],在這種情況下,last區(qū)間是已知完成的最后一個(gè)epoch,或 在此期間osd徹底關(guān)閉。如果可能的話,將last推送到osd被標(biāo)記為down時(shí)的epoch。

lost_at用來允許build_prior不等待一個(gè)osd恢復(fù)的情況下進(jìn)行。在某些情況下,進(jìn)度可能被阻止, 因?yàn)閛sd可能包含更新(即,pg可能在一個(gè)區(qū)間內(nèi)丟失讀寫)。如果osd無法在線,我們可以在已知丟失一些 確認(rèn)寫的情況下讓強(qiáng)制進(jìn)行。如果osd過會(huì)又好了,那也沒關(guān)系,但是這些寫依然會(huì)丟失(不同的對(duì)象會(huì)被 丟棄)。

2.osd_xinfo_t

struct osd_xinfo_t {utime_t down_stamp;float laggy_probability;__u32 laggy_interval;uint64_t features;__u32 old_weight;osd_xinfo_t() : laggy_probability(0), laggy_interval(0),features(0), old_weight(0) {} ... };

osd_xinfo_t結(jié)構(gòu)為OSD的一些擴(kuò)展信息

字段解釋:

  • down_stamp: osd被標(biāo)記為down時(shí)的時(shí)間戳

  • laggy_probability: 滯后概率,編碼為__u32,0表示沒有滯后,0xffffffff表示滯后

  • laggy_interval: 被標(biāo)記為滯后和恢復(fù)中的平均間隔

  • features: 應(yīng)該知道的osd所支持的特性

  • old_weight: 自動(dòng)標(biāo)記為out之前的權(quán)重

3.OSDMap

class OSDMap { public:class Incremental {...}; private:uuid_d fsid;epoch_t epoch; // what epoch of the osd cluster descriptor is thisutime_t created, modified; // epoch start timeint32_t pool_max; // the largest pool num, everuint32_t flags;int num_osd; // not saved; see calc_num_osdsint num_up_osd; // not saved; see calc_num_osdsint num_in_osd; // not saved; see calc_num_osdsint32_t max_osd;vector<uint8_t> osd_state;struct addrs_s {vector<ceph::shared_ptr<entity_addr_t> > client_addr;vector<ceph::shared_ptr<entity_addr_t> > cluster_addr;vector<ceph::shared_ptr<entity_addr_t> > hb_back_addr;vector<ceph::shared_ptr<entity_addr_t> > hb_front_addr;entity_addr_t blank;};ceph::shared_ptr<addrs_s> osd_addrs;vector<__u32> osd_weight;vector<osd_info_t> osd_info;ceph::shared_ptr< map<pg_t,vector<int32_t> > > pg_temp;ceph::shared_ptr< map<pg_t,int32_t > > primary_temp;ceph::shared_ptr< vector<__u32> > osd_primary_affinity;map<int64_t,pg_pool_t> pools;map<int64_t,string> pool_name;map<string,map<string,string> > erasure_code_profiles;map<string,int64_t> name_pool;ceph::shared_ptr< vector<uuid_d> > osd_uuid;vector<osd_xinfo_t> osd_xinfo;ceph::unordered_map<entity_addr_t,utime_t> blacklist;epoch_t cluster_snapshot_epoch;string cluster_snapshot;bool new_blacklist_entries;mutable uint64_t cached_up_osd_features;mutable bool crc_defined;mutable uint32_t crc; ...public:ceph::shared_ptr<CrushWrapper> crush; ... }

OSDMap結(jié)構(gòu)存儲(chǔ)了包括集群id,epoch信息,創(chuàng)建及修改時(shí)間,pool信息,OSD信息(總的OSD,up的 OSD以及已經(jīng)加入集群的OSD)等等。

字段解釋:

  • fsid: 集群id

  • created, modified: epoch開始時(shí)間

  • pool_max: 從開始到現(xiàn)在的最大的pool id

  • pg_temp: 臨時(shí)pg映射(比如重建)

  • primary_temp: 臨時(shí)primary映射

  • flags: OSD的標(biāo)志位(以jewel為例,常見的標(biāo)志位有sortbitwise,require_jewel_osds),后 面會(huì)詳細(xì)敘述

標(biāo)志位在這里的作用是標(biāo)識(shí)OSD集群的當(dāng)前的一些狀態(tài),在使用ceph -s命令的時(shí)候會(huì)連同OSD信息(總 的OSD,up的OSD以及已經(jīng)加入集群的OSD)一起輸出,方便第一時(shí)間了解到一些異常情況。

另外,比如要設(shè)置OSD不進(jìn)行數(shù)據(jù)清洗,可以通過ceph命令設(shè)置標(biāo)志位為noscrub及nodeep-scrub

[root@cephdev ]# ceph osd set noscrub [root@cephdev ]# ceph osd set nodeep-scrub

之后,再次查看集群狀態(tài)的時(shí)候就會(huì)發(fā)現(xiàn)多了這兩個(gè)標(biāo)志位:

[root@cephdev ]# ceph -s cluster a7aaeb51-63d4-4a07-9e5f-b94d970a686ehealth HEALTH_WARNnoscrub,nodeep-scrub,sortbitwise,require_jewel_osds flag(s) setmonmap e1: 1 mons at {a=127.0.0.1:6789/0}election epoch 4, quorum 0 aosdmap e10: 1 osds: 1 up, 1 inflags noscrub,nodeep-scrub,sortbitwise,require_jewel_osdspgmap v12042: 8 pgs, 1 pools, 0 bytes data, 0 objects840 MB used, 425 GB / 426 GB avail8 active+clean

標(biāo)志位解釋:

  • nearfull: 磁盤快滿了

  • full: 磁盤已經(jīng)滿了

  • pauserd: 暫停所有讀

  • pausewr: 暫停所有寫

  • pauserec: 暫停恢復(fù)

  • noup: 禁止OSD啟動(dòng)

  • nodown: 禁止標(biāo)記OSD為down

  • noout: 禁止OSD自動(dòng)標(biāo)記為out

  • noin: 禁止OSD自動(dòng)標(biāo)記為in

  • nobakfill: 禁止OSD進(jìn)行數(shù)據(jù)回填

  • norebalance: 禁止OSD回填,除非pg降級(jí)

  • norecover: 禁止OSD恢復(fù)和回填

  • noscrub: 設(shè)置OSD不進(jìn)行數(shù)據(jù)清洗

  • nodeep-scrub: 設(shè)置OSD不進(jìn)行數(shù)據(jù)的深度清洗

  • notieragent: 禁止tiering agent

  • sortbitwise: 使用hobject_t按位排序

  • require_jewel_osds: 這個(gè)標(biāo)記從J版開始有,標(biāo)志當(dāng)前OSD的版本,升級(jí)的時(shí)候有用

4.Incremental

class Incremental { public:/// feature bits we were encoded with. the subsequent OSDMap/// encoding should match.uint64_t encode_features;uuid_d fsid;epoch_t epoch; // new epoch; we are a diff from epoch-1 to epochutime_t modified;int64_t new_pool_max; //incremented by the OSDMonitor on each pool createint32_t new_flags;// full (rare)bufferlist fullmap; // in lieu of below.bufferlist crush;// incrementalint32_t new_max_osd;map<int64_t,pg_pool_t> new_pools;map<int64_t,string> new_pool_names;set<int64_t> old_pools;map<string,map<string,string> > new_erasure_code_profiles;vector<string> old_erasure_code_profiles;map<int32_t,entity_addr_t> new_up_client;map<int32_t,entity_addr_t> new_up_cluster;map<int32_t,uint8_t> new_state; // XORed onto previous state.map<int32_t,uint32_t> new_weight;map<pg_t,vector<int32_t> > new_pg_temp; // [] to removemap<pg_t, int32_t> new_primary_temp; // [-1] to removemap<int32_t,uint32_t> new_primary_affinity;map<int32_t,epoch_t> new_up_thru;map<int32_t,pair<epoch_t,epoch_t> > new_last_clean_interval;map<int32_t,epoch_t> new_lost;map<int32_t,uuid_d> new_uuid;map<int32_t,osd_xinfo_t> new_xinfo;map<entity_addr_t,utime_t> new_blacklist;vector<entity_addr_t> old_blacklist;map<int32_t, entity_addr_t> new_hb_back_up;map<int32_t, entity_addr_t> new_hb_front_up;string cluster_snapshot;mutable bool have_crc; ///< crc values are defineduint32_t full_crc; ///< crc of the resulting OSDMapmutable uint32_t inc_crc; ///< crc of this incremental }

結(jié)構(gòu)Incremental表示OSDMap的增量版本

字段解釋:

  • encode_features: 編碼的特征位,隨后的OSDMap編碼應(yīng)該匹配

  • epoch: 新的epoch,從epoch-1到epoch的差異

  • new_pool_max: 當(dāng)每個(gè)pool被創(chuàng)建時(shí)由OSDMonitor增加

  • fullmap: 代替變量crush

  • have_crc: crc值定義時(shí)為true

  • inc_crc: 該增量的crc

三、MOSDMap消息

該消息用來獲取OSDMap信息。

四、OSDMap更新機(jī)制

在部署Monitor的時(shí)候,Monitor的KeyValueDB中只保存有epoch為1的osdmap,此時(shí)并沒有osd在集 群中,當(dāng)有OSD向Monitor去申請(qǐng)加入集群的時(shí)候,Monitor會(huì)將該OSD記錄在OSDMap中并寫入 KeyValueDB中。同時(shí),當(dāng)OSD有更新的時(shí)候,Monitor也會(huì)向OSD發(fā)送消息,然后OSD在 handle_osd_map中處理該消息。

當(dāng)部署OSD的時(shí)候,OSD::mkfs期間,會(huì)在OSD數(shù)據(jù)目錄創(chuàng)建meta目錄并初始化,當(dāng)OSD申請(qǐng)加入Ceph進(jìn) 群成功后,該目錄中就會(huì)存儲(chǔ)有每個(gè)epoch的OSDMap信息。

五、OSDMap要點(diǎn)分析

六、獲取OSDMap

Ceph提供了一個(gè)命令行工具osdmaptool,能讓你創(chuàng)建,查看和操作OSD映射關(guān)系。更重要的是,使用該 工具能獲取和導(dǎo)入Crushmap,并能模擬OSD的分布。

對(duì)于OSD來說,它保存了每個(gè)epoch時(shí)的OSDMap信息,默認(rèn)存放在OSD數(shù)據(jù)目錄的current/meta中。

1.查看當(dāng)前集群最新epoch的OSDMap信息

使用ceph osd dump命令可以查看當(dāng)前最新epoch的OSDMap信息。另外,確認(rèn)當(dāng)前OSDMap的最新 epoch后,在OSD數(shù)據(jù)目錄的meta目錄下找到以osdmap.{epoch}開頭的文件即是。查看OSDMap信息, 使用--print參數(shù)即可。

osdmaptool --print osdmap.736__0_AC955C85__noneosdmaptool: osdmap file 'osdmap.736__0_AC955C85__none' epoch 736 fsid d9650900-aa7a-465a-a483-a1e80e7c7efa created 2016-11-05 23:03:48.070572 modified 2017-03-16 10:12:26.756716 flags sortbitwise,require_jewel_osds,require_kraken_osdspool 7 'ssd' replicated size 3 min_size 1 crush_ruleset 0 object_hash rjenkinspg_num 320 pgp_num 320 last_change 578 flags hashpspool stripe_width 0removed_snaps [1~3] pool 19 'images' replicated size 3 min_size 1 crush_ruleset 0 object_hashrjenkins pg_num 2 pgp_num 2 last_change 620 flags hashpspool stripe_width 0removed_snaps [1~3]max_osd 6 osd.0 down out weight 0 up_from 393 up_thru 383 down_at 394 last_clean_interval[389,389)192.168.108.11:6800/2582901 192.168.108.11:6801/2582901 192.168.108.11:6802/2582901 192. 168.108.11:6803/2582901 autoout,exists cfc90fe4-952c-495a-9b25-3d81b4cf441e osd.1 up in weight 1 up_from 726 up_thru 735 down_at 724 last_clean_interval[717,725) 192.168.108.11:6800/1937953 192.168.108.11:6805/2937953192.168.108.11:6809/2937953 192. 168.108.11:6821/2937953 exists,up 6c614571-47db-490e-8f98-184e0e963430 osd.2 up in weight 1 up_from 735 up_thru 735 down_at 733 last_clean_interval[648,734) 192.168.108.12:6804/312646 192.168.108.12:6801/5312646192.168.108.12:6802/5312646 192.168.108.12:6803/5312646 exists,upe1ed8e95-3900-491d-8f30-a6db0259698a osd.3 up in weight 1 up_from 731 up_thru 735 down_at 729 last_clean_interval[636,730) 192.168.108.12:6800/1675 192.168.108.12:6809/9001675192.168.108.12:6810/9001675 192.168.108.12:6811/9001675 exists,upf9d5146d-5a77-4d8f-b893-50860fc50f02 osd.4 down out weight 0 up_from 250 up_thru 346 down_at 348 last_clean_interval[236,248) 192.168.108.13:6800/286476 192.168.108.13:6801/286476192.168.108.13:6802/286476 192.168.108.13:6803/286476 autoout,exists e4158fd4-84c6-41c6-b231-f4335edb9ff8 osd.5 down out weight 0 up_from 643 up_thru 649 down_at 651 last_clean_interval[566,567) 192.168.108.13:6801/3857339 192.168.108.13:6802/3857339192.168.108.13:6803/3857339 192. 168.108.13:6804/3857339 autoout,exists 9a17c533-24e0-4742-a977-2fdb14fd5415pg_temp 7.1 [1,3,2] ...

如上所示,OSDMap中包含有當(dāng)前map的epoch,集群id,創(chuàng)建修改時(shí)間,標(biāo)志位,pool id,pool name, 副本數(shù),最小副本數(shù),使用的crush規(guī)則,pg和pgp數(shù)量,osd數(shù)量,各個(gè)osd在集群中的狀態(tài),權(quán)值, pg_temp映射關(guān)系等等。

注意:OSD中存儲(chǔ)的OSDMap文件是Monitor維護(hù)的OSDMap的持久化形式,相當(dāng)于log的作用。在Monitor 端,從epoch為1到當(dāng)前epoch的所有的集群Map信息都會(huì)在Monitor的KeyValueDB中存儲(chǔ)。

七、與OSDMap相關(guān)的參數(shù)配置

mon_osd_cache_size

  • 描述:OSDMaps的緩存大小,不依賴于底層的存儲(chǔ)緩存

  • 類型:int

  • 默認(rèn)值:10

mon_osd_allow_primary_temp

  • 描述:允許在OSDMap中設(shè)置primary_temp

  • 類型:bool

  • 默認(rèn)值:false

mon_osd_prime_pg_temp

  • 描述:prime osdmap with pg mapping changes

  • 類型:bool

  • 默認(rèn)值:true

mon_min_osdmap_epochs

  • 描述:

  • 類型:int

  • 默認(rèn)值:500

osd_map_message_max

  • 描述:每個(gè)MOSDMap消息最大的map數(shù)

  • 類型:int

  • 默認(rèn)值:100

osd_map_dedup

  • 描述:允許刪除OSDMap里的重復(fù)項(xiàng)

  • 類型:bool

  • 默認(rèn)值:true

osd_map_cache_size

  • 描述:緩存的OSDMap個(gè)數(shù)

  • 類型:int

  • 默認(rèn)值:200

八、疑點(diǎn)

1.is_up_acting_osd_shard

messenger 建立連接的時(shí)候bind的socket addr和socket? port的指定

public_messenger->bind() | -- | AsyncMessenger::bind() | -- | -- | Processor::bind()AsyncMessenger::bindv() {AsyncMessenger::bindv(){std::set<int> avoid_ports;entity_addrvec_t bound_addrs;unsigned i = 0;for (auto &&p : processors){int r = p->bind(bind_addrs, avoid_ports, &bound_addrs);}} }

int Processor::bind(const entity_addrvec_t &bind_addrs,
const std::set<int>& avoid_ports,
entity_addrvec_t* bound_addrs)
{

……

//try a range of ports 在給定的端口范圍內(nèi),找出一個(gè)沒有被本進(jìn)程使用過的端口,且能綁定上的for (int port = msgr->cct->_conf->ms_bind_port_min;port <= msgr->cct->_conf->ms_bind_port_max;port++) {if (avoid_ports.count(port))continue;

listen_addr.set_port(port);//找到一個(gè)端口,接下來嘗試bind
worker->center.submit_to(
worker->center.get_id(),
[this, k, &listen_addr, &opts, &r]() {

r = worker->listen(listen_addr, k, opts, &listen_sockets[k]);

}, false);

if (r == 0)
break;

}

if (r < 0) {
lderr(msgr->cct) << __func__ << " unable to bind to " << listen_addr
<< " on any port in range "
<< msgr->cct->_conf->ms_bind_port_min
<< "-" << msgr->cct->_conf->ms_bind_port_max << ": "
<< cpp_strerror(r) << dendl;
listen_addr.set_port(0); // Clear port before retry, otherwise we shall fail again.
continue;
}

ldout(msgr->cct, 10) << __func__ << " bound on random port "
}

bind完成之后,將傳入?yún)?shù)bind_addrs里的對(duì)應(yīng)的v的port設(shè)置為 (ms_bind_port_min到ms_bind_port_max之間的某端口號(hào),然后交給 worker->listen,如果listen成功就返回,傳入?yún)?shù)entity_addrvec_t bind_addrs里的對(duì)應(yīng)的v的port的值,就為剛才設(shè)置的值,傳出去了

int Processor::bind(const entity_addrvec_t &bind_addrs,……)
auto& listen_addr = bound_addrs->v[k];

listen_addr.set_port(port);
r = worker->listen(listen_addr, k, opts, &listen_sockets[k]);

int RDMAWorker::listen(entity_addr_t &sa, unsigned addr_slot,
const SocketOptions &opt,ServerSocket *sock)
p = new RDMAServerSocketImpl(cct, ib, dispatcher, this, sa, addr_slot);
int r = p->listen(sa, opt);

int RDMAServerSocketImpl::listen(entity_addr_t &sa, const SocketOptions &opt) { int rc = 0; server_setup_socket = net.create_socket(sa.get_family(), true);if (server_setup_socket < 0) { rc = -errno; lderr(cct) << __func__ << " failed to create server socket: " << cpp_strerror(errno) << dendl; return rc; }rc = net.set_nonblock(server_setup_socket);if (rc < 0) { goto err;}rc = net.set_socket_options(server_setup_socket, opt.nodelay, opt.rcbuf_size);if (rc < 0) { goto err;}rc = ::bind(server_setup_socket, sa.get_sockaddr(), sa.get_sockaddr_len()); <----------這里if (rc < 0) { rc = -errno; ldout(cct, 10) << __func__ << " unable to bind to " << sa.get_sockaddr() << " on port " << sa.get_port() << ": " << cpp_strerror(errno) << dendl; goto err;}rc = ::listen(server_setup_socket, cct->_conf->ms_tcp_listen_backlog);if (rc < 0) { rc = -errno; lderr(cct) << __func__ << " unable to listen on " << sa << ": " << cpp_strerror(errno) << dendl; goto err;}ldout(cct, 20) << __func__ << " bind to " << sa.get_sockaddr() << " on port " << sa.get_port() << dendl; return 0;err: ::close(server_setup_socket); server_setup_socket = -1; return rc;}

port 在 entity_addr_t 結(jié)構(gòu)體里

/*
?* an entity's network address.
?* includes a random value that prevents it from being reused.
?* thus identifies a particular process instance.
?* ipv4 for now.
?*/
struct entity_addr_t {
? typedef enum {
? ? TYPE_NONE = 0,
? ? TYPE_LEGACY = 1, ?///< legacy msgr1 protocol (ceph jewel and older)
? ? TYPE_MSGR2 = 2, ? ///< msgr2 protocol (new in ceph kraken)
? ? TYPE_ANY = 3, ?///< ambiguous
? } type_t;
? static const type_t TYPE_DEFAULT = TYPE_MSGR2;
? static std::string_view get_type_name(int t) {
? ? switch (t) {
? ? case TYPE_NONE: return "none";
? ? case TYPE_LEGACY: return "v1";
? ? case TYPE_MSGR2: return "v2";
? ? case TYPE_ANY: return "any";
? ? default: return "???";
? ? }
? };

? __u32 type;
? __u32 nonce;
? union {
? ? sockaddr sa;
? ? sockaddr_in sin;
? ? sockaddr_in6 sin6;
? } u;

? entity_addr_t() : type(0), nonce(0) {
? ? memset(&u, 0, sizeof(u));
? }
? entity_addr_t(__u32 _type, __u32 _nonce) : type(_type), nonce(_nonce) {
? ? memset(&u, 0, sizeof(u));
? }
? explicit entity_addr_t(const ceph_entity_addr &o) {
? ? type = o.type;
? ? nonce = o.nonce;
? ? memcpy(&u, &o.in_addr, sizeof(u));
#if !defined(__FreeBSD__)
? ? u.sa.sa_family = ntohs(u.sa.sa_family);
#endif
? }

? uint32_t get_type() const { return type; }
? void set_type(uint32_t t) { type = t; }
? bool is_legacy() const { return type == TYPE_LEGACY; }
? bool is_msgr2() const { return type == TYPE_MSGR2; }
? bool is_any() const { return type == TYPE_ANY; }

? __u32 get_nonce() const { return nonce; }
? void set_nonce(__u32 n) { nonce = n; }

? int get_family() const {
? ? return u.sa.sa_family;
? }
? void set_family(int f) {
? ? u.sa.sa_family = f;
? }

? bool is_ipv4() const {
? ? return u.sa.sa_family == AF_INET;
? }
? bool is_ipv6() const {
? ? return u.sa.sa_family == AF_INET6;
? }

? sockaddr_in &in4_addr() {
? ? return u.sin;
? }
? const sockaddr_in &in4_addr() const{
? ? return u.sin;
? }
? sockaddr_in6 &in6_addr(){
? ? return u.sin6;
? }
? const sockaddr_in6 &in6_addr() const{
? ? return u.sin6;
? }
? const sockaddr *get_sockaddr() const {
? ? return &u.sa;
? }
? size_t get_sockaddr_len() const {
? ? switch (u.sa.sa_family) {
? ? case AF_INET:
? ? ? return sizeof(u.sin);
? ? case AF_INET6:
? ? ? return sizeof(u.sin6);
? ? }
? ? return sizeof(u);
? }
? bool set_sockaddr(const struct sockaddr *sa)
? {
? ? switch (sa->sa_family) {
? ? case AF_INET:
? ? ? // pre-zero, since we're only copying a portion of the source
? ? ? memset(&u, 0, sizeof(u));
? ? ? memcpy(&u.sin, sa, sizeof(u.sin));
? ? ? break;
? ? case AF_INET6:
? ? ? // pre-zero, since we're only copying a portion of the source
? ? ? memset(&u, 0, sizeof(u));
? ? ? memcpy(&u.sin6, sa, sizeof(u.sin6));
? ? ? break;
? ? case AF_UNSPEC:
? ? ? memset(&u, 0, sizeof(u));
? ? ? break;
? ? default:
? ? ? return false;
? ? }
? ? return true;
? }

? sockaddr_storage get_sockaddr_storage() const {
? ? sockaddr_storage ss;
? ? memcpy(&ss, &u, sizeof(u));
? ? memset((char*)&ss + sizeof(u), 0, sizeof(ss) - sizeof(u));
? ? return ss;
? }

? void set_in4_quad(int pos, int val) {
? ? u.sin.sin_family = AF_INET;
? ? unsigned char *ipq = (unsigned char*)&u.sin.sin_addr.s_addr;
? ? ipq[pos] = val;
? } void set_port(int port) {
? ? switch (u.sa.sa_family) {
? ? case AF_INET: u.sin.sin_port = htons(port);
? ? ? break;
? ? case AF_INET6: ? u.sin6.sin6_port = htons(port);
? ? ? break;
? ? default:
? ? ? ceph_abort();
? ? }
? }
? int get_port() const {
? ? switch (u.sa.sa_family) {
? ? case AF_INET:
? ? ? return ntohs(u.sin.sin_port);
? ? case AF_INET6:
? ? ? return ntohs(u.sin6.sin6_port);
? ? }
? ? return 0;
? }

? operator ceph_entity_addr() const {
? ? ceph_entity_addr a;
? ? a.type = 0;
? ? a.nonce = nonce;
? ? a.in_addr = get_sockaddr_storage();
#if !defined(__FreeBSD__)
? ? a.in_addr.ss_family = htons(a.in_addr.ss_family);
#endif
? ? return a;
? }

? bool probably_equals(const entity_addr_t &o) const {
? ? if (get_port() != o.get_port())
? ? ? return false;
? ? if (get_nonce() != o.get_nonce())
? ? ? return false;
? ? if (is_blank_ip() || o.is_blank_ip())
? ? ? return true;
? ? if (memcmp(&u, &o.u, sizeof(u)) == 0)
? ? ? return true;
? ? return false;
? }

? bool is_same_host(const entity_addr_t &o) const {
? ? if (u.sa.sa_family != o.u.sa.sa_family)
? ? ? return false;
? ? if (u.sa.sa_family == AF_INET)
? ? ? return u.sin.sin_addr.s_addr == o.u.sin.sin_addr.s_addr;
? ? if (u.sa.sa_family == AF_INET6)
? ? ? return memcmp(u.sin6.sin6_addr.s6_addr,
?? ??? ? ? ?o.u.sin6.sin6_addr.s6_addr,
?? ??? ? ? ?sizeof(u.sin6.sin6_addr.s6_addr)) == 0;
? ? return false;
? }

? bool is_blank_ip() const {
? ? switch (u.sa.sa_family) {
? ? case AF_INET:
? ? ? return u.sin.sin_addr.s_addr == INADDR_ANY;
? ? case AF_INET6:
? ? ? return memcmp(&u.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0;
? ? default:
? ? ? return true;
? ? }
? }

? bool is_ip() const {
? ? switch (u.sa.sa_family) {
? ? case AF_INET:
? ? case AF_INET6:
? ? ? return true;
? ? default:
? ? ? return false;
? ? }
? }

? std::string ip_only_to_str() const;

? std::string get_legacy_str() const {
? ? std::ostringstream ss;
? ? ss << get_sockaddr() << "/" << get_nonce();
? ? return ss.str();
? }

? bool parse(const std::string_view s);
? bool parse(const char *s, const char **end = 0, int type=0);

? void decode_legacy_addr_after_marker(ceph::buffer::list::const_iterator& bl)
? {
? ? using ceph::decode;
? ? __u8 marker;
? ? __u16 rest;
? ? decode(marker, bl);
? ? decode(rest, bl);
? ? decode(nonce, bl);
? ? sockaddr_storage ss;
? ? decode(ss, bl);
? ? set_sockaddr((sockaddr*)&ss);
? ? if (get_family() == AF_UNSPEC) {
? ? ? type = TYPE_NONE;
? ? } else {
? ? ? type = TYPE_LEGACY;
? ? }
? }

? // Right now, these only deal with sockaddr_storage that have only family and content.
? // Apparently on BSD there is also an ss_len that we need to handle; this requires
? // broader study

? void encode(ceph::buffer::list& bl, uint64_t features) const {
? ? using ceph::encode;
? ? if ((features & CEPH_FEATURE_MSG_ADDR2) == 0) {
? ? ? encode((__u32)0, bl);
? ? ? encode(nonce, bl);
? ? ? sockaddr_storage ss = get_sockaddr_storage();
? ? ? encode(ss, bl);
? ? ? return;
? ? }
? ? encode((__u8)1, bl);
? ? ENCODE_START(1, 1, bl);
? ? if (HAVE_FEATURE(features, SERVER_NAUTILUS)) {
? ? ? encode(type, bl);
? ? } else {
? ? ? // map any -> legacy for old clients. ?this is primary for the benefit
? ? ? // of OSDMap's blocklist, but is reasonable in general since any: is
? ? ? // meaningless for pre-nautilus clients or daemons.
? ? ? auto t = type;
? ? ? if (t == TYPE_ANY) {
?? ?t = TYPE_LEGACY;
? ? ? }
? ? ? encode(t, bl);
? ? }
? ? encode(nonce, bl);
? ? __u32 elen = get_sockaddr_len();
#if (__FreeBSD__) || defined(__APPLE__)
? ? ? elen -= sizeof(u.sa.sa_len);
#endif
? ? encode(elen, bl);
? ? if (elen) {
? ? ? uint16_t ss_family = u.sa.sa_family;

? ? ? encode(ss_family, bl);
? ? ? elen -= sizeof(u.sa.sa_family);
? ? ? bl.append(u.sa.sa_data, elen);
? ? }
? ? ENCODE_FINISH(bl);
? }
? void decode(ceph::buffer::list::const_iterator& bl) {
? ? using ceph::decode;
? ? __u8 marker;
? ? decode(marker, bl);
? ? if (marker == 0) {
? ? ? decode_legacy_addr_after_marker(bl);
? ? ? return;
? ? }
? ? if (marker != 1)
? ? ? throw ceph::buffer::malformed_input("entity_addr_t marker != 1");
? ? DECODE_START(1, bl);
? ? decode(type, bl);
? ? decode(nonce, bl);
? ? __u32 elen;
? ? decode(elen, bl);
? ? if (elen) {
#if defined(__FreeBSD__) || defined(__APPLE__)
? ? ? u.sa.sa_len = 0;
#endif
? ? ? uint16_t ss_family;
? ? ? if (elen < sizeof(ss_family)) {
?? ?throw ceph::buffer::malformed_input("elen smaller than family len");
? ? ? }
? ? ? decode(ss_family, bl);
? ? ? u.sa.sa_family = ss_family;
? ? ? elen -= sizeof(ss_family);
? ? ? if (elen > get_sockaddr_len() - sizeof(u.sa.sa_family)) {
?? ?throw ceph::buffer::malformed_input("elen exceeds sockaddr len");
? ? ? }
? ? ? bl.copy(elen, u.sa.sa_data);
? ? }
? ? DECODE_FINISH(bl);
? }

? void dump(ceph::Formatter *f) const;

? static void generate_test_instances(std::list<entity_addr_t*>& o);
}

總結(jié)

以上是生活随笔為你收集整理的【ceph】Ceph 存储中 PGMap、OSDMap 和xxMap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。