集羣中的主機通過選舉過程由Looking狀態變爲了Leadering或Following狀態。而這些狀態之間轉移的條件是什麼呢?先來個直觀的,上狀態圖。node
圖 4.1 Cocklebur選舉過程當中的狀態圖算法
接下來咱們對上面的狀態圖進行逐個分析,而且作出簡要的解釋說明。若是你對一些概念有所遺忘,請查閱「Cocklebur選舉」一章中的名詞解釋。spa
表 4-1 狀態轉移連接表3d
狀態轉移連接日誌 |
條件對象 |
解釋blog |
Start->Looking進程 |
啓動同步 |
主機進程實例一旦被啓動都設置爲Looking狀態源碼 |
Looking->Following |
收到對本身加ACK鎖主機的Lead消息,或者肯定已經存在一個穩定的正常工做的多數派 |
發現以前給本身加ACK鎖的候選者已經成爲Leader,說明必定存在一個多數派以其做爲Leader,故能夠變爲Following。另外當一個Looker發現已經存在一個穩定的服務集羣(有穩定的Leader和Follower),則它會自動變爲Follower加入集羣 |
Looking->Leadering |
得到多數派的ACK鎖 |
改進段屬於Paxos的第二階段,候選者贏得了多數派(包括本身)的投票,那麼他就多數派申請ACK鎖,若是應答容許的節點依然可構成多數派,則說明候選者能夠作爲Leader |
Following->Looking |
Leader狀態改變爲非Leadering或向Leader申請租約超時 |
當發現Leader已經不是Leader,或者在超時內鏈接不到Leader,那麼說明Leader已經失效,則須要從新選舉 |
Leadering->Looking |
租約有效的Follower不足majority-1 |
Leader維護這租約表,若是有效的Follower很多於majority-1,那麼算上Leader本身可構成多數派。若是不知足此條件,則從新選舉 |
*->end |
宕機 |
主機宕機,任何狀態歸於結束 |
狀態轉移控制流程在源碼的Cocklebur.cpp中的process方法中,只用到了一個switch語句。lookForLeader()、Following()、Leadering(),這三個方法完成了三態的運行流程,而每個方法結束以前,已經確保了全局狀態是否改變,這樣在某個方法結束後,process方法就能夠直接運行當前狀態應該運行的控制流程。
lookForLeader()的算法邏輯咱們已經在選舉一章中分析過,接下來介紹一下Following()、Leadering()兩個方法。這兩個方法分別屬於Follower對象與Leader對象。
Follower每隔一段時間向Leader申請租約。所謂申請租約本質上是一種超時鎖,而Follower申請的像是一種讀鎖,擁有租約以後Follower才能保證能從Leader同步到最新數據。Follower經過心跳的方式向Leader發送一個消息,Cocklebur中消息的結構以下:
struct HBMSG {
1: string my_host_name,
2: i32 cur_node_mode,
3: i64 xid,
}
這是使用thrift腳本格式去定義的結構體,它包含三個部分:消息發送者的主機名my_host_name、當前狀態cur_node_mode、發送者的數據版本xid。
Follower根據配置定時向Leader發送一個HBMSG,同時也接收一個Leader返回的HBMSG。若是發現返回的HBMSG中Leader狀態已經改變,那麼它將結束Following流程。Follower的Client實現了一種超時機制,若是鏈接超時,HBMSG的my_host_name將被置爲空串,這說明Leader失效,那麼也將結束Following流程。
而xid的做用就是告知Follower與Leader雙方是否須要同步數據。若是Follower發現數據版本xid小於Leader,而且Follower接到Client的同步(sync方法的調用)請求,那麼則能夠主動的去Leader同步。通常狀況下Follower的xid可能會小於Leader一段時間,由於向Follower推送數據是Leader主動完成的。
當集羣剛剛選舉完畢,Leader每每還不會對外提供讀寫服務,由於Cocklebur認爲在對外服務以前還有可能加入xid更大的Follower。那麼此時Leader便會主動的去pull數據。也就是說Follower只有在client請求其向Leader同步時,Follower纔會pull數據。
Leader剛剛進入Leadering狀態時會爲每一個多數派其餘成員初始化一個租約列表,每一個成員的租約期限有個默認值。以後就是不停的去減小租約表中的租約。若是接到了某個Follower申請租約的請求,Leader會爲其從新審定租約期限。租約表就好像是一排沙漏,不停的漏沙子,而Follower按照必定時間間隔往本身漏斗中填一把沙子,保證不漏光。若是漏光了,那麼Leader則會將其拿掉。若是有新的Follower加入,Leader則爲其申請一個新的租約計時器。
當租約表中的Follower與本身構不成一個多數派時,Leader將會退出Leadering流程。固然這裏面能夠對一些超時選項加以配置。好比租約表爲空以後能夠不當即退出,租約被申請屢次以後能夠提升租約期限等等。
上文中提到了Leader在決定是否要對外服務以前同步數據的問題。選舉完成後,Leader不立刻讓集羣對外服務,而是等待一段時間看看時候還有新的Follower加入。若是這期間加入了Follower,Leader會輪流對其監察(經過HBMSG的方式),若檢查發現xid比本身的大,則開始pull數據。數據操做後文會逐漸講解。
最後你們可能會有一些疑問,Xid較大,必定表明他數據最新且正確嗎?其實在進行同步時Leader會有一些機制去監察數據是不是正確的,整個集羣在寫數據時每一個操做都記錄在日誌中,在任什麼時候候集羣中的每一個節點都是一個狀態機,只要經歷的步驟順序正確,那麼必定能夠保證xid的正確性(經歷有限相同狀態轉移以後狀態一致)。該部分也將會在後文中闡述。