理解Ceph的存儲設計

jopen 9年前發布 | 15K 次閱讀 Ceph 分布式/云計算/大數據
 

在大部分中心化存儲系統中(如GFS)中,通常有一個中心節點管理整個系統元數據的更新、協調節點之間的數據復制,檢測并處理節點故障以及后續的數據遷移工作。Ceph認為將所有的管理工作全部交一個節點不利于整個系統的擴展:1)單個節點存儲、計算以及網絡傳輸能力有限,容易成為性能瓶頸;2)中心節點本身存在單點故障的風險。如果讓數據節點參與管理工作,充分利用數據節點CPU/內存/網絡資源,就能提升系統性能改善其擴展性。 Ceph將這種擁有部分自主管理能力的數據節點稱為智能設備-OSD(Object Storage Device)。

中心化存儲系統中,中心節點擁有全局數據分布的信息并且能夠基于這些信息進行數據分布的決策。如果讓OSD也具有這種能力,那么OSD也必須知道整個系統的數據分布信息。GFS采用細粒度的數據分布設計,即每個Block都擁有的不同的數據分布,這種方式的缺點在于整個系統數據分布信息數據量非常大(即使通過增大Block的大小,也無法將全部的數據分布信息存儲在單機之上)。Ceph采用一種更粗粒度的數據分布設計,數據(Object)首先會被映射到一個PG(Placement Group),各個PG被指派到不同的OSDs中(同一個PG中的全部對象都被存儲在同樣的物理OSDs中)。這種設計減少了數據分布信息數據量大小,方便這些信息在網絡上的傳輸并且只占用OSD極少的內存,這就允許各個OSD自主根據這些信息進行全局統一的數據分布決策。Ceph將這些信息以及系統所有 OSD的狀態等合起來稱為Cluster Map,當OSD或者系統網絡發生變化的時候,Cluster Map也需要跟著發生變化。例如當某個OSD故障或者網絡連接中斷的時候,需要將該OSD上的PGs遷移到其他的OSD上,Cluster Map要進行相應的調整,并且這些調整需要一致的反應到全部的OSD的本地Cluster Map緩存。

Ceph通過一個Monitor集群來維護Cluster Map的主備份,所有的OSD均連接到該集群上去獲取對應的拷貝,Monitor集群內部通過Paxos協議來維護Cluster Map的數據一致性。實現上Monitor采用了Lease機制簡化Paxos協議,這種簡化協議僅允許系統中只有一個Monitor能夠進行寫入,這個 Monitor稱為Leader。初始時所有的Monitor先選舉出一個Leader,該Leader將協調其他Monitor的Cluster Map的更新。每隔固定周期Leader向其他Monitor發放Lease,持有Lease的Monitor才能夠對外提供讀服務(否則認為該 Monitor上的數據已經過時,不能提供讀服務)。當Leader宕機時,其他的Monitor會重新選舉Leader。OSDs可以連接到任意一個 Monitor上發送寫請求,該請求會被轉發到Leader上由Leader進行處理后,同步到各個Monitor中。當OSD狀態發生變化的時候,Leader運行CRUSH算法重新計算PG的分布變更,并將這些變更同步給其他的Monitor。Monitor集群不會主動去檢測OSD的狀態,OSD也不會定期向Monitor匯報狀態,OSD狀態報告主要是通過下面三種方式:1)Client在讀取某個OSD內容時發現OSD宕機,并報告給Monitor集群;2)OSD在給其他OSD同步數據或者交換心跳信息時發現OSD宕機,報告給Monitor集群;3)新上線或者恢復的OSD主動向Monitor集群報道自己新的狀態。這樣設計的原因在于Ceph需要支持PB級的數據存儲,系統中可能有成千上萬的OSD,正常情況下并不需要這些檢測網絡信息,保證Monitor集群最小化有利于系統的擴展性。同樣Cluster Map的增量變化大部分情況也不是由Monitor集群直接同步給各個OSD,而是各個OSD中相互同步最新的Cluster Map信息。每個Cluster Map都有一個epoch,每次Cluster Map發生變化,epoch都會進行增加。Client和OSD以及OSD和OSD進行各種交互的時候(如Client向OSD發送讀寫請求,OSD向 OSD發送數據備份請求以及心跳消息)都會帶上發送者Cluster Map的epoch。epoch較新的一方會自動計算兩個epoch之間的增量差異,并將差異發送給epoch較老的一方,后者更新自己的Cluster Map信息。Client或者OSD初始連接集群的時候才會向Monitor拉取全量的Cluster Map信息。

在GFS中客戶端每次向系統新寫入一個Block都需要NameNode為該Block分配副本存放信息,這當然會加重NameNode的負擔并影響客戶端寫入性能。在Ceph中Object的副本存放信息是由PG來決定的,Ceph的Monitor集群會計算每個PG所對應的OSD,并將這個信息保存在Cluster Map中。只要系統的OSD狀態沒有發生變更,那么屬于同一個PG的Object的副本存放信息就是不變的。Client在讀寫一個對象的時候,首先根據其對象標識計算對應的pg_id,然后查找Cluster Map中該pg_id對應的active OSD List,并選擇其中第一個作為Primary OSD發送讀寫請求。該OSD收到寫請求的時候先檢查比對Client的自己的epoch,如果一致則查找pg_id對應的active OSD list,并將副本信息轉發給對應的OSD。如果Client的epoch比自己的老,則OSD計算Cluster Map的差異,并將差異返回給Client,讓Client將請求發送到正確的OSD上。如果Client的epoch比自己的新,則OSD向 Client請求最新的Cluster Map。Client根據自己所有的Cluster Map信息計算差異并返回給OSD。OSD在獲取最新的Cluster Map之后會了解的自己角色的變化(可能之前該OSD并不存儲該PG,由于其他OSD故障等狀態變化,Monitor集群將新的PG分配給了自己),并根據相應的角色采取不同的策略。如果該OSD是PG的Replica,則該OSD向該PG當前的Primary發送請求獲取對應的Replica內容(這在 Chain或者Splan復制模式比較有可能,因為讀取發生在active list的最末尾的OSD上,在Primary-Copy模式下讀取發生在Primary上)。如果該OSD是該PG的Primary(說明PG的 Primary發生了變化),那么該OSD會阻塞這次Client的IO請求,直到該PG正確的恢復了該對象的數據。恢復過程分為兩個階段:Peering和Recovery。在Peering階段中,每個OSD副本會向PG當前的Primary發送Notify消息,該消息PG最新的更新,PG log以及最近的epoch。這個階段中Primary OSD將會了解到所有的PG的信息,包括Object的最新版本以及對應OSD。在Recovery階段當前的Primary會從對應的OSD中拉取缺失的Object,并將最新的內容推送給其他缺失的OSD中。正常情況下,為了避免Client讀到老的Replica(這種情況可能發生在網絡分區使得 Client和連接的OSD與其他大部分OSD斷開),要求同一個PG的OSD之間要互相周期性發送心跳消息。如果提供讀服務的OSD一定時間內沒有收到其他OSD的心跳消息,那么它認為自己數據過時,將會阻塞Client的請求。這些心跳信息還承擔故障檢測的功能,當某個OSD能夠確定另外一個OSD宕機后(不是簡單的二者之間網絡不可達),它會向Monitor請求將該OSD狀態標志為down,monitor收到請求后會轉發到Leader進行處理。

【參考資料】

[1] Weil S A, Leung A W, Brandt S A, et al. Rados: a scalable, reliable storage service for petabyte-scale storage clusters[C]//Proceedings of the 2nd international workshop on Petascale data storage: held in conjunction with Supercomputing’07. ACM, 2007: 35-44.

[2] http://docs.ceph.com/docs/master/architecture/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!