史上最全的Ceph介紹、原理、架構
1. Ceph架構簡介及使用場景介紹
1.1 Ceph簡介
Ceph是一個統一的分散式儲存系統,設計初衷是提供較好的效能、可靠性和可擴充套件性。
Ceph專案最早起源於Sage就讀博士期間的工作(最早的成果於2004年發表),並隨後貢獻給開源社群。在經過了數年的發展之後,目前已得到眾多雲計算廠商的支援並被廣泛應用。RedHat及OpenStack都可與Ceph整合以支援虛擬機器映象的後端儲存。
1.2 Ceph特點
高效能
a. 摒棄了傳統的集中式儲存元資料定址的方案,採用CRUSH演算法,資料分佈均衡,並行度高。
b.考慮了容災域的隔離,能夠實現各類負載的副本放置規則,例如跨機房、機架感知等。
c. 能夠支援上千個儲存節點的規模,支援TB到PB級的資料。
高可用性
a. 副本數可以靈活控制。
b. 支援故障域分隔,資料強一致性。
c. 多種故障場景自動進行修復自愈。
d. 沒有單點故障,自動管理。
高可擴充套件性
a. 去中心化。
b. 擴充套件靈活。
c. 隨著節點增加而線性增長。
特性豐富
a. 支援三種儲存介面:塊儲存、檔案儲存、物件儲存。
b. 支援自定義介面,支援多種語言驅動。
1.3 Ceph架構
支援三種介面:
Object:有原生的API,而且也相容Swift和S3的API。
Block:支援精簡配置、快照、克隆。
File:Posix介面,支援快照。
rados
1.4 Ceph核心元件及概念介紹
Monitor
一個Ceph叢集需要多個Monitor組成的小叢集,它們通過Paxos同步資料,用來儲存OSD的元資料。
OSD
OSD全稱Object Storage Device,也就是負責響應客戶端請求返回具體資料的程序。一個Ceph叢集一般都有很多個OSD。
MDS
MDS全稱Ceph Metadata Server,是CephFS服務依賴的元資料服務。
Object
Ceph最底層的儲存單元是Object物件,每個Object包含元資料和原始資料。
PG
PG全稱Placement Grouops,是一個邏輯的概念,一個PG包含多個OSD。引入PG這一層其實是為了更好的分配資料和定位資料。
RADOS
RADOS全稱Reliable Autonomic Distributed Object Store,是Ceph叢集的精華,使用者實現資料分配、Failover等叢集操作。
Libradio
Librados是Rados提供庫,因為RADOS是協議很難直接訪問,因此上層的RBD、RGW和CephFS都是通過librados訪問的,目前提供PHP、Ruby、Java、Python、C和C++支援。
CRUSH
CRUSH是Ceph使用的資料分佈演算法,類似一致性雜湊,讓資料分配到預期的地方。
RBD
RBD全稱RADOS block device,是Ceph對外提供的塊裝置服務。
RGW
RGW全稱RADOS gateway,是Ceph對外提供的物件儲存服務,介面與S3和Swift相容。
CephFS
CephFS全稱Ceph File System,是Ceph對外提供的檔案系統服務。
1.5 三種儲存型別-塊儲存
rbd
典型裝置: 磁碟陣列,硬碟
主要是將裸磁碟空間對映給主機使用的。
優點:
通過Raid與LVM等手段,對資料提供了保護。
多塊廉價的硬碟組合起來,提高容量。
多塊磁碟組合出來的邏輯盤,提升讀寫效率。
缺點:
採用SAN架構組網時,光纖交換機,造價成本高。
主機之間無法共享資料。
使用場景:
docker容器、虛擬機器磁碟儲存分配。
日誌儲存。
檔案儲存。
…
1.6 三種儲存型別-檔案儲存
fs
典型裝置: FTP、NFS伺服器
為了克服塊儲存檔案無法共享的問題,所以有了檔案儲存。
在伺服器上架設FTP與NFS服務,就是檔案儲存。
優點:
造價低,隨便一臺機器就可以了。
方便檔案共享。
缺點:
讀寫速率低。
傳輸速率慢。
使用場景:
日誌儲存。
有目錄結構的檔案儲存。
…
1.7 三種儲存型別-物件儲存
rgw
典型裝置: 內建大容量硬碟的分散式伺服器(swift, s3)
多臺伺服器內建大容量硬碟,安裝上物件儲存管理軟體,對外提供讀寫訪問功能。
優點:
具備塊儲存的讀寫高速。
具備檔案儲存的共享等特性。
使用場景: (適合更新變動較少的資料)
圖片儲存。
視訊儲存。
…
2. Ceph IO流程及資料分佈
rados_io_1
2.1 正常IO流程圖
ceph_io_2
步驟:
1. client 建立cluster handler。
2. client 讀取配置檔案。
3. client 連線上monitor,獲取叢集map資訊。
4. client 讀寫io 根據crshmap 演算法請求對應的主osd資料節點。
5. 主osd資料節點同時寫入另外兩個副本節點資料。
6. 等待主節點以及另外兩個副本節點寫完資料狀態。
7. 主節點及副本節點寫入狀態都成功後,返回給client,io寫入完成。
2.2 新主IO流程圖
說明:
如果新加入的OSD1取代了原有的 OSD4成為 Primary OSD, 由於 OSD1 上未建立 PG , 不存在資料,那麼 PG 上的 I/O 無法進行,怎樣工作的呢?
ceph_io_3
步驟:
1. client連線monitor獲取叢集map資訊。
2. 同時新主osd1由於沒有pg資料會主動上報monitor告知讓osd2臨時接替為主。
3. 臨時主osd2會把資料全量同步給新主osd1。
4. client IO讀寫直接連線臨時主osd2進行讀寫。
5. osd2收到讀寫io,同時寫入另外兩副本節點。
6. 等待osd2以及另外兩副本寫入成功。
7. osd2三份資料都寫入成功返回給client, 此時client io讀寫完畢。
8. 如果osd1資料同步完畢,臨時主osd2會交出主角色。
9. osd1成為主節點,osd2變成副本。
2.3 Ceph IO演算法流程
ceph_io_4
1. File使用者需要讀寫的檔案。File->Object對映:
a. ino (File的元資料,File的唯一id)。
b. ono(File切分產生的某個object的序號,預設以4M切分一個塊大小)。
c. oid(object id: ino + ono)。
2. Object是RADOS需要的物件。Ceph指定一個靜態hash函式計算oid的值,將oid對映成一個近似均勻分佈的偽隨機值,然後和mask按位相與,得到pgid。Object->PG對映:
a. hash(oid) & mask-> pgid 。
b. mask = PG總數m(m為2的整數冪)-1 。
3. PG(Placement Group),用途是對object的儲存進行組織和位置對映, (類似於redis cluster裡面的slot的概念) 一個PG裡面會有很多object。採用CRUSH演算法,將pgid代入其中,然後得到一組OSD。PG->OSD對映:
a. CRUSH(pgid)->(osd1,osd2,osd3) 。
2.4 Ceph IO虛擬碼流程
locator = object_name
obj_hash = hash(locator)
pg = obj_hash % num_pg
osds_for_pg = crush(pg) # returns a list of osdsprimary = osds_for_pg[0]
replicas = osds_for_pg[1:]
2.5 Ceph RBD IO流程
ceph_rbd_io
步驟:
1. 客戶端建立一個pool,需要為這個pool指定pg的數量。
2. 建立pool/image rbd裝置進行掛載。
3. 使用者寫入的資料進行切塊,每個塊的大小預設為4M,並且每個塊都有一個名字,名字就是object+序號。
4. 將每個object通過pg進行副本位置的分配。
5. pg根據cursh演算法會尋找3個osd,把這個object分別儲存在這三個osd上。
6. osd上實際是把底層的disk進行了格式化操作,一般部署工具會將它格式化為xfs檔案系統。
7. object的儲存就變成了儲存一個文rbd0.object1.file。
2.6 Ceph RBD IO框架圖
ceph_rbd_io1
客戶端寫資料osd過程:
1. 採用的是librbd的形式,使用librbd建立一個塊裝置,向這個塊裝置中寫入資料。
2. 在客戶端本地同過呼叫librados介面,然後經過pool,rbd,object、pg進行層層對映,在PG這一層中,可以知道資料儲存在哪3個OSD上,這3個OSD分為主從的關係。
3. 客戶端與primay OSD建立SOCKET 通訊,將要寫入的資料傳給primary OSD,由primary OSD再將資料傳送給其他replica OSD資料節點。
2.7 Ceph Pool和PG分佈情況
ceph_pool_pg
說明:
pool是ceph儲存資料時的邏輯分割槽,它起到namespace的作用。
每個pool包含一定數量(可配置)的PG。
PG裡的物件被對映到不同的Object上。
pool是分佈到整個叢集的。
pool可以做故障隔離域,根據不同的使用者場景不一進行隔離。
2.8 Ceph 資料擴容PG分佈
場景資料遷移流程:
現狀3個OSD, 4個PG
擴容到4個OSD, 4個PG
現狀:
ceph_recory_1
擴容後:
ceph_io_recry2
說明
每個OSD上分佈很多PG, 並且每個PG會自動散落在不同的OSD上。如果擴容那麼相應的PG會進行遷移到新的OSD上,保證PG數量的均衡。
3. Ceph心跳機制
3.1 心跳介紹
心跳是用於節點間檢測對方是否故障的,以便及時發現故障節點進入相應的故障處理流程。
問題:
故障檢測時間和心跳報文帶來的負載之間做權衡。
心跳頻率太高則過多的心跳報文會影響系統性能。
心跳頻率過低則會延長髮現故障節點的時間,從而影響系統的可用性。
故障檢測策略應該能夠做到:
及時:節點發生異常如宕機或網路中斷時,叢集可以在可接受的時間範圍內感知。
適當的壓力:包括對節點的壓力,和對網路的壓力。
容忍網路抖動:網路偶爾延遲。
擴散機制:節點存活狀態改變導致的元資訊變化需要通過某種機制擴散到整個叢集。
3.2 Ceph 心跳檢測
ceph_heartbeat_1
OSD節點會監聽public、cluster、front和back四個埠
public埠:監聽來自Monitor和Client的連線。
cluster埠:監聽來自OSD Peer的連線。
front埠:供客戶端連線叢集使用的網絡卡, 這裡臨時給叢集內部之間進行心跳。
back埠:供客叢集內部使用的網絡卡。叢集內部之間進行心跳。
hbclient:傳送ping心跳的messenger。
3.3 Ceph OSD之間相互心跳檢測
ceph_heartbeat_osd
步驟:
同一個PG內OSD互相心跳,他們互相傳送PING/PONG資訊。
每隔6s檢測一次(實際會在這個基礎上加一個隨機時間來避免峰值)。
20s沒有檢測到心跳回復,加入failure佇列。
3.4 Ceph OSD與Mon心跳檢測
ceph_heartbeat_mon
OSD報告給Monitor:
OSD有事件發生時(比如故障、PG變更)。
自身啟動5秒內。
OSD週期性的上報給Monito
OSD檢查failure_queue中的夥伴OSD失敗資訊。
向Monitor傳送失效報告,並將失敗資訊加入failure_pending佇列,然後將其從failure_queue移除。
收到來自failure_queue或者failure_pending中的OSD的心跳時,將其從兩個佇列中移除,並告知Monitor取消之前的失效報告。
當發生與Monitor網路重連時,會將failure_pending中的錯誤報告加回到failure_queue中,並再次傳送給Monitor。
Monitor統計下線OSD
Monitor收集來自OSD的夥伴失效報告。
當錯誤報告指向的OSD失效超過一定閾值,且有足夠多的OSD報告其失效時,將該OSD下線。
3.5 Ceph心跳檢測總結
Ceph通過夥伴OSD彙報失效節點和Monitor統計來自OSD的心跳兩種方式判定OSD節點失效。
及時:夥伴OSD可以在秒級發現節點失效並彙報Monitor,並在幾分鐘內由Monitor將失效OSD下線。
適當的壓力:由於有夥伴OSD彙報機制,Monitor與OSD之間的心跳統計更像是一種保險措施,因此OSD向Monitor傳送心跳的間隔可以長達600秒,Monitor的檢測閾值也可以長達900秒。Ceph實際上是將故障檢測過程中中心節點的壓力分散到所有的OSD上,以此提高中心節點Monitor的可靠性,進而提高整個叢集的可擴充套件性。
容忍網路抖動:Monitor收到OSD對其夥伴OSD的彙報後,並沒有馬上將目標OSD下線,而是週期性的等待幾個條件:
目標OSD的失效時間大於通過固定量osd_heartbeat_grace和歷史網路條件動態確定的閾值。
來自不同主機的彙報達到mon_osd_min_down_reporters。
滿足前兩個條件前失效彙報沒有被源OSD取消。
擴散:作為中心節點的Monitor並沒有在更新OSDMap後嘗試廣播通知所有的OSD和Client,而是惰性的等待OSD和Client來獲取。以此來減少Monitor壓力並簡化互動邏輯。
4. Ceph通訊框架
4.1 Ceph通訊框架種類介紹
網路通訊框架三種不同的實現方式:
Simple執行緒模式
特點:每一個網路連結,都會建立兩個執行緒,一個用於接收,一個用於傳送。
缺點:大量的連結會產生大量的執行緒,會消耗CPU資源,影響效能。Async事件的I/O多路複用模式
特點:這種是目前網路通訊中廣泛採用的方式。k版預設已經使用Asnyc了。XIO方式使用了開源的網路通訊庫accelio來實現
特點:這種方式需要依賴第三方的庫accelio穩定性,目前處於試驗階段。
4.2 Ceph通訊框架設計模式
設計模式(Subscribe/Publish):
訂閱釋出模式又名觀察者模式,它意圖是“定義物件間的一種一對多的依賴關係,
當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新”。
4.3 Ceph通訊框架流程圖
ceph_message
步驟:
Accepter監聽peer的請求, 呼叫 SimpleMessenger::add_accept_pipe() 建立新的 Pipe 到 SimpleMessenger::pipes 來處理該請求。
Pipe用於訊息的讀取和傳送。該類主要有兩個元件,Pipe::Reader,Pipe::Writer用來處理訊息讀取和傳送。
Messenger作為訊息的釋出者, 各個 Dispatcher 子類作為訊息的訂閱者, Messenger 收到訊息之後, 通過 Pipe 讀取訊息,然後轉給 Dispatcher 處理。
Dispatcher是訂閱者的基類,具體的訂閱後端繼承該類,初始化的時候通過 Messenger::add_dispatcher_tail/head 註冊到 Messenger::dispatchers. 收到訊息後,通知該類處理。
DispatchQueue該類用來快取收到的訊息, 然後喚醒 DispatchQueue::dispatch_thread 執行緒找到後端的 Dispatch 處理訊息。
ceph_message_2
4.4 Ceph通訊框架類圖
ceph_message_3
4.5 Ceph通訊資料格式
通訊協議格式需要雙方約定資料格式。
訊息的內容主要分為三部分:
header //訊息頭,型別訊息的信封
user data //需要傳送的實際資料
payload //操作儲存元資料
middle //預留欄位
data //讀寫資料
footer //訊息的結束標記
class Message : public RefCountedObject {
protected:
ceph_msg_header header; // 訊息頭
ceph_msg_footer footer; // 訊息尾
bufferlist payload; // "front" unaligned blob
bufferlist middle; // "middle" unaligned blob
bufferlist data; // data payload (page-alignment will be preserved where possible)
/* recv_stamp is set when the Messenger starts reading the
* Message off the wire */
utime_t recv_stamp; //開始接收資料的時間戳
/* dispatch_stamp is set when the Messenger starts calling dispatch() on
* its endpoints */
utime_t dispatch_stamp; //dispatch 的時間戳
/* throttle_stamp is the point at which we got throttle */
utime_t throttle_stamp; //獲取throttle 的slot的時間戳
/* time at which message was fully read */
utime_t recv_complete_stamp; //接收完成的時間戳
ConnectionRef connection; //網路連線
uint32_t magic = 0; //訊息的魔術字
bi::list_member_hook<> dispatch_q; //boost::intrusive 成員欄位
};
struct ceph_msg_header {
__le64 seq; // 當前session內 訊息的唯一 序號
__le64 tid; // 訊息的全域性唯一的 id
__le16 type; // 訊息型別
__le16 priority; // 優先順序
__le16 version; // 版本號
__le32 front_len; // payload 的長度
__le32 middle_len;// middle 的長度
__le32 data_len; // data 的 長度
__le16 data_off; // 物件的資料偏移量
struct ceph_entity_name src; //訊息源
/* oldest code we think can decode this. unknown if zero. */
__le16 compat_version;
__le16 reserved;
__le32 crc; /* header crc32c */
} __attribute__ ((packed));
struct ceph_msg_footer {
__le32 front_crc, middle_crc, data_crc; //crc校驗碼
__le64 sig; //訊息的64位signature
__u8 flags; //結束標誌
} __attribute__ ((packed));
5. Ceph CRUSH演算法
5.1 資料分佈演算法挑戰
資料分佈和負載均衡:
a. 資料分佈均衡,使資料能均勻的分佈到各個節點上。
b. 負載均衡,使資料訪問讀寫操作的負載在各個節點和磁碟的負載均衡。
靈活應對叢集伸縮
a. 系統可以方便的增加或者刪除節點裝置,並且對節點失效進行處理。
b. 增加或者刪除節點裝置後,能自動實現資料的均衡,並且儘可能少的遷移資料。
支援大規模叢集
a. 要求資料分佈演算法維護的元資料相對較小,並且計算量不能太大。隨著叢集規模的增 加,資料分佈演算法開銷相對比較小。
5.2 Ceph CRUSH演算法說明
CRUSH演算法的全稱為:Controlled Scalable Decentralized Placement of Replicated Data,可控的、可擴充套件的、分散式的副本資料放置演算法。
pg到OSD的對映的過程演算法叫做CRUSH 演算法。(一個Object需要儲存三個副本,也就是需要儲存在三個osd上)。
CRUSH演算法是一個偽隨機的過程,他可以從所有的OSD中,隨機性選擇一個OSD集合,但是同一個PG每次隨機選擇的結果是不變的,也就是對映的OSD集合是固定的。
5.3 Ceph CRUSH演算法原理
CRUSH演算法因子:
層次化的Cluster Map
反映了儲存系統層級的物理拓撲結構。定義了OSD叢集具有層級關係的 靜態拓撲結構。OSD層級使得 CRUSH演算法在選擇OSD時實現了機架感知能力,也就是通過規則定義, 使得副本可以分佈在不同的機 架、不同的機房中、提供資料的安全性 。
Placement Rules
決定了一個PG的物件副本如何選擇的規則,通過這些可以自己設定規則,使用者可以自定義設定副本在叢集中的分佈。
5.3.1 層級化的Cluster Map
ceph_crush
CRUSH Map是一個樹形結構,OSDMap更多記錄的是OSDMap的屬性(epoch/fsid/pool資訊以及osd的ip等等)。
葉子節點是device(也就是osd),其他的節點稱為bucket節點,這些bucket都是虛構的節點,可以根據物理結構進行抽象,當然樹形結構只有一個最終的根節點稱之為root節點,中間虛擬的bucket節點可以是資料中心抽象、機房抽象、機架抽象、主機抽象等。
5.3.2 資料分佈策略Placement Rules
資料分佈策略Placement Rules主要有特點:
a. 從CRUSH Map中的哪個節點開始查詢
b. 使用那個節點作為故障隔離域
c. 定位副本的搜尋模式(廣度優先 or 深度優先)
rule replicated_ruleset #規則集的命名,建立pool時可以指定rule集
{
ruleset 0 #rules集的編號,順序編即可
type replicated #定義pool型別為replicated(還有erasure模式)
min_size 1 #pool中最小指定的副本數量不能小1
max_size 10 #pool中最大指定的副本數量不能大於10
step take default #查詢bucket入口點,一般是root型別的bucket
step chooseleaf firstn 0 type host #選擇一個host,並遞迴選擇葉子節點osd
step emit #結束
}
5.3.3 Bucket隨機演算法型別
ceph_bucket
一般的buckets:適合所有子節點權重相同,而且很少新增刪除item。
list buckets:適用於叢集擴充套件型別。增加item,產生最優的資料移動,查詢item,時間複雜度O(n)。
tree buckets:查詢負責度是O (log n), 新增刪除葉子節點時,其他節點node_id不變。
straw buckets:允許所有項通過類似抽籤的方式來與其他項公平“競爭”。定位副本時,bucket中的每一項都對應一個隨機長度的straw,且擁有最長長度的straw會獲得勝利(被選中),新增或者重新計算,子樹之間的資料移動提供最優的解決方案。
5.4 CRUSH演算法案例
說明:
叢集中有部分sas和ssd磁碟,現在有個業務線效能及可用性優先順序高於其他業務線,能否讓這個高優業務線的資料都存放在ssd磁碟上。
普通使用者:
ceph_sas.png
高優使用者:
ssd
配置規則:
ceph_crush1
6. 定製化Ceph RBD QOS
6.1 QOS介紹
QoS (Quality of Service,服務質量)起源於網路技術,它用來解決網路延遲和阻塞等問題,能夠為指定的網路通訊提供更好的服務能力。
問題:
我們總的Ceph叢集的iIO能力是有限的,比如頻寬,IOPS。如何避免使用者爭取資源,如果保證叢集所有使用者資源的高可用性,以及如何保證高優使用者資源的可用性。所以我們需要把有限的IO能力合理分配。
6.2 Ceph IO操作型別
ClientOp:來自客戶端的讀寫I/O請求。
SubOp:osd之間的I/O請求。主要包括由客戶端I/O產生的副本間資料讀寫請求,以及由資料同步、資料掃描、負載均衡等引起的I/O請求。
SnapTrim:快照資料刪除。從客戶端傳送快照刪除命令後,刪除相關元資料便直接返回,之後由後臺執行緒刪除真實的快照資料。通過控制snaptrim的速率間接控制刪除速率。
Scrub:用於發現物件的靜默資料錯誤,掃描元資料的Scrub和物件整體掃描的deep Scrub。
Recovery:資料恢復和遷移。叢集擴/縮容、osd失效/從新加入等過程。
6.3 Ceph 官方QOS原理
ceph_mclok_qos
mClock是一種基於時間標籤的I/O排程演算法,最先被Vmware提出來的用於集中式管理的儲存系統。(目前官方QOS模組屬於半成品)。
基本思想:
reservation 預留,表示客戶端獲得的最低I/O資源。
weight 權重,表示客戶端所佔共享I/O資源的比重。
limit 上限,表示客戶端可獲得的最高I/O資源。
6.4 定製化QOS原理
6.4.1 令牌桶演算法介紹
ceph_token_qos
基於令牌桶演算法(TokenBucket)實現了一套簡單有效的qos功能,滿足了雲平臺使用者的核心需求。
基本思想:
按特定的速率向令牌桶投放令牌。
根據預設的匹配規則先對報文進行分類,不符合匹配規則的報文不需要經過令牌桶的處理,直接傳送。
符合匹配規則的報文,則需要令牌桶進行處理。當桶中有足夠的令牌則報文可以被繼續傳送下去,同時令牌桶中的令牌量按報文的長度做相應的減少。
當令牌桶中的令牌不足時,報文將不能被髮送,只有等到桶中生成了新的令牌,報文才可以傳送。這就可以限制報文的流量只能是小於等於令牌生成的速度,達到限制流量的目的。
6.4.2 RBD令牌桶演算法流程
ceph_token1
步驟:
使用者發起請求非同步IO到達Image中。
請求到達ImageRequestWQ佇列中。
在ImageRequestWQ出佇列的時候加入令牌桶演算法TokenBucket。
通過令牌桶演算法進行限速,然後傳送給ImageRequest進行處理。
6.4.3 RBD令牌桶演算法框架圖
現有框架圖:
ceph_qos2
令牌圖演算法框架圖:
ceph_qos_token2
作者:李航,多年的底層開發經驗,在高效能nginx開發和分散式快取redis cluster有著豐富的經驗,目前從事Ceph工作兩年左右。先後在58同城、汽車之家、優酷土豆集團工作。 目前供職於滴滴基礎平臺運維部 負責分散式Ceph叢集開發及運維等工作。個人主要關注的技術領域:高效能Nginx開發、分散式快取、分散式儲存。
出處:https://www.jianshu.com/p/cc3ece850433
版權申明:內容來源網路,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝。
架構文摘
ID:ArchDigest
網際網路應用架構丨架構技術丨大型網站丨大資料丨機器學習
更多精彩文章,請點選下方:閱讀原文