轉自于:http://blog.csdn.net/changtao381/article/details/8698935
其結構如下:在src 裡,
網絡通信: msg 裡面 包括了網絡傳輸的代碼, message 目錄裡定義了 傳輸的消息格式。
中繼資料伺服器:
mds 目錄 包括了metadata server 的代碼
資料伺服器:
os 目錄裡包含了 object store 的代碼
osd 目錄包括了 object storage device 的代碼
用戶端:
osdc 目錄裡包括跨網絡通路 osd的 代碼
librados 包括了對象存儲的用戶端操作的代碼
librbd,rgw, client 用戶端代碼,其代碼都是基于librados之上。
監控:Ceph Monitor
mon 目錄裡包括了 Ceph Monitor的代碼
CRUSH 算法:
cursh 目錄裡包括了 cursh 算法的代碼
核心就是上述的代碼,當然還有其它一些的輔助性的代碼:
common: 一些公用的類和函數
cls: OSD的一個插件機制,可以在對象上原子的執行一些複雜的操作。 感覺有點像OpenC++的反射機制,總之是一種測試和調試機制。
Ceph最大的特點是分布式的中繼資料伺服器 通過CRUSH,一種拟算法來配置設定檔案的locaiton,其核心是 RADOS(resilient automatic distributed object storage),一個對象叢集存儲,本身提供對象的高可用,錯誤檢測和修複功能。
其設計思想有一些創新點:
第一,資料的定位是通過CRUSH算法來實作的。
傳統的,或者通常的并行檔案系統,資料的定位的資訊是儲存在檔案的metadata 中的, 也就是inode結構中,通過到metadata server上去擷取資料分布的資訊。而在Ceph中,是通過CRUSH 這個算法來提供資料定位的;
這和GlusterFS的思想是相同的,GlusterFS 是通過Elastic Hash,類似于DHT的算法實作的。這就有點像P2P存儲,所謂的完全對稱的存儲,這種設計架構最大的優點是,其理論上可以做到 線性擴充的能力(line scale)。
在GlusterFS架構中,是完全去掉了metadata server,這就導緻GlusterFS檔案系統上的中繼資料操作,例如ls, stat操作非常慢,要去各個stripe的節點上收集相關的中繼資料資訊後聚合後的結果。在Ceph中,為了消除完全的p2p設計,提供了metadata server 服務,提供檔案級别的中繼資料服務,而中繼資料服務中的檔案資料定位由CRUSH算法代替。
第二,中繼資料伺服器可以提供叢集metadata server 服務。
隻要當我們了解了其結構後,感覺并沒有太大的特點。中繼資料伺服器一般就用來存儲檔案和目錄的資訊,提供統一的命名服務。 在Ceph中,中繼資料 的存儲inode 和 dentry的,以及日志都是在 對象存儲叢集RADOS中存儲,這就使得 metadata的 持久化都 是在遠端的RADOS中完成,metadata server 不儲存狀态,隻是緩存最近的inode 和 dentry項,當metadata server 失效後,其所所有資訊都可以從RADOS中擷取,可以比較容易恢複。
其實, 也上兩點,并沒有什麼特别的地方。 我覺得,CEPH最核心的,就是RADOS就是RADOS(resilient automatic distributed object storage). 其resilient 指的是可以輕松擴充,automatic 指的是其對象存儲叢集可以處理failover, failure recovery。RADOS 對象叢集其對外提供了一個高可用的,可擴充的,對象叢集,從用戶端的角度看,就是一個統一命名空間的對象存儲。
下面我們重點介紹一下RADOS這個Ceph的核心系統。
用來監控叢集中所有節點的狀态資訊,完成類似配置服務的功能。在Ceph裡,配置主要就是cluster map ,其儲存叢集所有節點資訊,并和所有的節點保持心跳,來監控所有的節點狀态。
其通過Paxos算法實作實作自身的高可用,也就是說,這個Ceph Monitor是不會有單點問題的。目前流行的zookeeper 的功能,以及實作都類似。
Ceph檔案系統中的資料和中繼資料都儲存在對象中。 對于對象存儲,通常的定義是:一個Object,由三部分組成(id,metadata,data),id是對象的辨別,這個不必多說。所謂的metadata,就是key/value的鍵值存儲,至于用來儲存什麼資訊,由檔案系統的語義定義。data就是實際存儲的資料。
Ceph的對象,包括四個部分(id,metadata,attribute,data),在Ceph裡,一個Object,實際就對應本地檔案系統的一個檔案,一個對象的attribute,也是key/value的鍵值對,其儲存在本地檔案系統的檔案的擴充屬性中。對象的metadata就是key/value的鍵值對,目前Ceph儲存在google開源的一個key/value存儲系統leveldb中,或者自己寫的一個key/value 存儲系統中。資料就儲存在對象的檔案中。對于一個對象的更新,都需要寫日志中來保持一個Object資料的一緻性(consistence),日志有一個單獨的裝置或者檔案來儲存。
一個PG(placement group)由一個OSD清單組成,OSD的個數,就是對象的副本數,一個三副本的PG就是一個主,兩個副本的OSD清單組成。
一個PG和OSD清單的映射關系,是通過CRUSH算法計算的,知道PG的id,和目前的cluster map,就可以通過CRUSH算法,計算出OSD清單。特别強調的是,一個PG是邏輯層概念,也就是說,一個OSD,可能同時是一個或者多個PG的主,同時是另一個PG的從。一個OSD處于多個PG組中。一個PG就是複制和修複的基本機關。每個OSD本地儲存其所在的PG清單就可以了,其它OSD可以通過輸入目前的該OSD儲存的cluster map 和 PG 的id ,通過CRUSH計算得出。
對于Ceph檔案系統,錯誤分兩類:一類是磁盤錯誤或者資料損壞( disk error or corruptted data), 這類錯誤OSD會自己報告和處理。(self report ); 第二類是OSD失去網絡連接配接導緻該OSD不可達(unreachable on the network)這種情況下需要主動檢測(active monitor),在同一個PG組中的其它OSD會發心跳資訊互相檢測。 這種檢測的一個優化的方法就是,當replication複制操作時,就可以順帶檢測,不用發單獨的消息來檢測,隻有一段時間沒有replication 操作時,才發ping消息裡檢測。
OSD的失效狀态有兩種:一種是down狀态,這種狀态下,被認為是臨時錯誤。 在這種情況下,如果是primay,其任務由下一個replicate接手。如果該OSD沒有迅速恢複(quickly recovery),那麼就被标記為out狀态,在這種狀态下,将有新的osd加入這個PG中。
如何标記一個OSD 從down狀态 标記為out狀态?由于網絡分區的問題,需要通過 Ceph Monitor 來裁定。
用戶端先寫主副本,然後同步到兩個從副本。主副本等待從副本的ack消息和apply消息。當主副本收到ack消息,說明寫操作已經寫在記憶體中完成,收到apply 消息,說明已經apply到磁盤上了。
如果在寫的過程中,主副本失效,按順序下一個從副本接管主副本的工作,這個時候是否傳回給用戶端寫正确?在這種情況下,用戶端隻是判斷正常工作的(acting)的 OSD的傳回結果,隻要所有正常工作的OSD傳回即認為成功,雖然這時候可能隻有兩副本成功。同時該臨時primay必須儲存所有操作的recovey隊列裡,如果原primay恢複,可以replay所有recovery隊列裡的操作,如果主副本從down到out狀态,也即是永久失效,臨時primay轉正,由臨時primay為正式primay,隻是需要加入一個新的OSD到該PG中。
如果是從副本失效,就比較簡單。臨時失效,主replay所有寫操作,如過永久失效,新加入一個OSD到PG中就可以了。
當有OSD失效,恢複或者增加一個新的OSD時,導緻OSD cluster map的變換。Ceph處理以上三種情況的政策是一緻的。為了恢複,ceph儲存了兩類資料,一個是每個OSD的一個version,另一個是PG修改的log,這個log包括PG修改的object 的名稱和version。
當一個OSD接收到cluster map的更新時:
1)檢查該OSD的所屬的PG,對每個PG,通過CRUSH算法,計算出主副本的三個OSD
2)如何該PG裡的OSD發生了改變,這時候,所有的replicate向主副本發送log,也就是每個對象最後的version,當primay 決定了最後各個對象的正确的狀态,并同步到所有副本上。
3)每個OSD獨立的決定,是從其它副本中恢複丢失或者過時的(missing or outdated)對象。 (如何恢複? 好像是整個對象全部拷貝,或者基于整個對象拷貝,但是用了一些類似于rsync的算法?目前還不清楚)
4)當OSD在恢複過程中,delay所有的請求,直到恢複成功。