在之前的一篇博客Ceph Monitor and Paxos中介紹了Ceph Monitor利用改進的Paxos算法,以集群的形式對外提供元信息管理服務。本文講分別從Ceph Monitor的架構,其初始化過程、選主過程、Recovery過程、讀寫過程、狀態(tài)轉換六個方面介紹Ceph Monitor的實現(xiàn)。本文假設讀者已經(jīng)了解Paxos算法的基本過程,了解Prepare、Promise、Commit、Accept、Quorum等概念。注意Ceph Monitor中的Accept概念其實相當于Paxos中的Promise。
架構

上圖所示是Ceph Monitor的結構圖,自下而上有以下幾個部分組成:
- DBStore層:數(shù)據(jù)的最終存儲組件,以leveldb為例;
- Paxos層:在集群上對上層提供一致的數(shù)據(jù)訪問邏輯,在這一層看來所有的數(shù)據(jù)都是kv;上層的多中PaxosService將不同的組件的map數(shù)據(jù)序列化為單條value,公用同一個paxos實例。
- PaxosService層:每個PaxosService代表集群的一種狀態(tài)信息。對應的,Ceph Moinitor中包含分別負責OSD Map,Monitor Map, PG Map, CRUSH Map的幾種PaxosService。PaxosService負責將自己對應的數(shù)據(jù)序列化為kv寫入Paxos層。Ceph集群所有與Monitor的交互最終都是在調用對應的PaxosSevice功能。
初始化

可以看出,Ceph Monitor在啟動節(jié)點端,主要做了三件事情:
- 自下而上依次初始化上述的三大組成部分:DBStroe,Paxos,PaxoService
- 初始化Messager,并向其中注冊命令執(zhí)行回調函數(shù)。Messager是Ceph中的網(wǎng)絡線程模塊,Messager會在收到網(wǎng)絡請求后,回調Moniotor在初始化階段注冊命令處理函數(shù)。
- Bootstrap過程在整個Monitor的生命周期中被反復調用,下面就重點介紹一下這個過程。
Boostrap
- 執(zhí)行Boostrap的Monitor節(jié)點會首先進入PROBING狀態(tài),并開始向所有monmap中其他節(jié)點發(fā)送Probing消息。
- 收到Probing消息的節(jié)點執(zhí)行Boostrap并回復Probing_ack,并給出自己的last_commit以及first_commit,其中first_commit指示當前機器的commit記錄中最早的一條,其存在使得單個節(jié)點上可以僅保存最近的幾條記錄。
- 收到Probing_ack的節(jié)點發(fā)現(xiàn)commit數(shù)據(jù)的差距早于對方first_commit,則主動發(fā)起全同步,并在之后重新Boostrap
- 收到超過半數(shù)的ack并不需要全同步時,則進入選主過程。
上述交互過程見下圖:

目的:可以看出,經(jīng)過了Boostrap過程,可以完成以下兩步保證:
- 可以與超過半數(shù)的節(jié)點通信;
- 節(jié)點間commit數(shù)據(jù)歷史差距不大。
選主
接著,節(jié)點進入選主過程:
- 將election_epoch加1,向Monmap中的所有其他節(jié)點發(fā)送Propose消息;
- 收到Propose消息的節(jié)點進入election狀態(tài)并僅對有更新的election_epoch且rank值大于自己的消息答復Ack。這里的rank簡單的由ip大小決定;
- 發(fā)送Propose的節(jié)點統(tǒng)計收到的Ack數(shù),超時時間內收到Monmap中大多數(shù)的ack后可進入victory過程,這些發(fā)送ack的節(jié)點形成quorum;
victory
- election_epoch加1,可以看出election_epoch的奇偶可以表示是否在選舉輪次;
- 向quorum中的所有節(jié)點發(fā)送VICTORY消息,并告知自己的epoch及quorum;
- 當前節(jié)點完成Election,進入Leader狀態(tài);
- 收到VICTORY消息的節(jié)點完成Election,進入Peon狀態(tài)
上述交互過程見下圖:

目的:可以看出,Monitor選主過程的目的如下:
- 簡單的根據(jù)ip大小選出leader,而并沒有考慮commit數(shù)據(jù)長度;
- 確定quroum,在此之前所有的操作都是針對Monmap內容的,直到這里才有了quroum,之后的所有Paxos操作便基于當前這個quorum了。
RECOVERY階段
經(jīng)過了上述的選主階段,便確定了leader,peon角色,以及quorum成員。在真正的開始一致性讀寫之前,還需要經(jīng)過RECOVERY階段:
- leader生成新的更大的新的pn,并通過collect消息發(fā)送給所有的quorum中成員;
- 收到collect消息的節(jié)點當pn大于自己已經(jīng)accept的最大pn時,接受并通過last消息返回自己的commit位置及uncommitted;
- leader收到last消息,更新自己的commit位置及數(shù)據(jù),并重復提升pn發(fā)送collect消息的過程,直到quorum中所有的節(jié)點都接受自己。
- 同時leader會根據(jù)收到的commit及uncommitted位置,分別用commit消息和begin消息更新對應的peon;
- leader向quorum中所有節(jié)點發(fā)送lease消息,使整個集群進入active狀態(tài)。
這個階段的交互過程如下圖:

目的:
- 將leader及quorum節(jié)點的數(shù)據(jù)更新到最新且一致;
- 整個集群進入可用狀態(tài)。
讀寫流程
經(jīng)過了上面的初始化、選主、恢復階段整個集群進入到一個非常正常的狀況,終于可以利用Paxos進行一致性地讀寫了,其中讀過程比較簡單,在lease內的所有quroum均可以提供服務。而所有的寫都會轉發(fā)給leader,寫過程如下:
- leader在本地記錄要提交的value,并向quroum中的所有節(jié)點發(fā)送begin消息,其中攜帶了要提交的value, accept_pn及l(fā)ast_commit;
- peon收到begin消息,如果accept過更高的pn則忽略,否則將value寫入db并返回accept消息。同時peon會將當前的lease過期掉,在下一次收到lease前不再提供服務;
- leader收到全部quorum的accept后進行commit。本地commit后向所有quorum節(jié)點發(fā)送commit消息;
- peon收到commit消息,本地commit數(shù)據(jù);
- leader通過lease消息將整個集群帶入到active狀態(tài)。
交互過程如下:

目的:
- 由leader發(fā)起propose,并依次完成寫入,一個value完成commit才會開始下一個;
- 通過lease分擔讀壓力。
數(shù)據(jù)存儲:我們知道commit以后的數(shù)據(jù)才算真正寫入到集群,那么為什么在begin過程中,leader和peon都會將數(shù)據(jù)寫入db呢?這是因為Ceph Montor利用db來完成了log和value兩部分數(shù)據(jù)的存儲,而commit時會將log數(shù)據(jù)反序列化后以value的格式重新存儲到db。
狀態(tài)
在Monitor的生命周期,貫穿于上述各個過程的包括兩個層面的狀態(tài)轉換,Monitor自身的狀態(tài),以及Monitor進入主從狀態(tài)后,其Paxos過程中的狀態(tài)。
Monitor狀態(tài)轉換

- STATE_PROBING:boostrap過程中節(jié)點間相互探測,發(fā)現(xiàn)數(shù)據(jù)差距;
- STATE_SYNCHRONIZING:當數(shù)據(jù)差距較大無法通過后續(xù)機制補齊時,進行全同步;
- STATE_ELECTING:Monitor在進行選主
- STATE_LEADER:當前Monitor成為leader
- STATE_PEON:非leader節(jié)點
Paxos狀態(tài)轉換

- STATE_RECOVERING:對應上述RECOVERING過程;
- STATE_ACTIVE:leader可以讀寫或peon擁有l(wèi)ease;
- STATE_UPDATING(STATE_UPDATING_PREVIOUS):向quroum發(fā)送begin,等待accept;
- STATE_WRITING(STATE_WRITING_PREVIOUS):收到accept
- STATE_REFRESH:本地提交并向quorum發(fā)送commit;
參考:
RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters