zookeeper paxos算法

原文出處:http://rdc.taobao.com/blog/cs/?p=162算法

本文主要介紹zookeeper中zookeeper Server leader的選舉,zookeeper在選舉leader的時候採用了paxos算法(主要是fast paxos),這裏主要介紹其中兩種:LeaderElection 和FastLeaderElection.網絡

咱們先要清楚如下幾點

  • 一個Server是如何知道其它的Server


在zookeeper中,一個zookeeper集羣有多少個Server是固定,每一個Server用於選舉的IP和PORT都在配置文件中
數據結構

  • 除了IP和PORT能標識一個Server外,還有沒有別的方法

每個Server都有一個數字編號,並且是惟一的,咱們根據配置文件中的配置來對每個Server進行編號,這一步在部署時須要人工去作,須要在存儲數據文件的目錄中建立一個文件叫myid的文件,並寫入本身的編號,這個編號在處理我提交的value相同頗有用spa

  • 成爲Leader的必要條件

得到n/2 + 1個Server贊成(這裏意思是n/2 + 1個Server要贊成擁有zxid是全部Server最大的哪一個Server)線程

  • zookeeper中選舉採用UDP仍是TCP

zookeeper中選舉主要是採用UDP,也一種實現是採用TCP,在這裏介紹的兩種實現採用的是UDPserver

  • zookeeper中有哪幾種狀態

LOOKING 初始化狀態對象

LEADING  領導者狀態blog

FOLLOWING  跟隨者狀態排序

  • 若是全部zxid都相同(例如: 剛初始化時),此時有可能不能造成n/2+1個Server,怎麼辦

zookeeper中每個Server都有一個ID,這個ID是不重複的,並且按大小排序,若是遇到這樣的狀況時,zookeeper就推薦ID最大的哪一個Server做爲Leader隊列

  • zookeeper中Leader怎麼知道Fllower還存活,Fllower怎麼知道Leader還存活

Leader定時向Fllower發ping消息,Fllower定時向Leader發ping消息,當發現Leader沒法ping通時,就改變本身的狀態(LOOKING),發起新的一輪選舉

名詞解釋

zookeeer Server: zookeeper中一個Server,如下簡稱Server

zxid(zookeeper transtion id): zookeeper 事務id,他是選舉過程當中可否成爲leader的關鍵因素,它決定當前Server要將本身這一票投給誰(也就是我在選舉過程當中的value,這只是其中一個,還有id)

myid/id(zookeeper server id): zookeeper server id ,他也是可否成爲leader的一個因素

epoch/logicalclock:他主要用於描述leader是否已經改變,每個Server中啓動都會有一個epoch,初始值爲0,當 開始新的一次選舉時epoch加1,選舉完成時 epoch加1。

tag/sequencer:消息編號

xid:隨機生成的一個數字,跟epoch功能相同

Fast Paxos消息流向圖與Basic Paxos的對比

消息流向圖

  • basic paxos 消息流向圖
Client   Proposer      Acceptor     Learner
   |         |          |  |  |       |  |
   X-------->|          |  |  |       |  |  Request
   |         X--------->|->|->|       |  |  Prepare(N)//向全部Server提議
   |         |<---------X--X--X       |  |  Promise(N,{Va,Vb,Vc})//向提議人回覆是否接受提議(若是不接受回到上一步)
   |         X--------->|->|->|       |  |  Accept!(N,Vn)//向全部人發送接受提議消息
   |         |<---------X--X--X------>|->|  Accepted(N,Vn)//向提議人回覆本身已經接受提議)
   |<---------------------------------X--X  Response
   |         |          |  |  |       |  |
  • fast paxos消息流向圖

沒有衝突的選舉過程

Client    Leader         Acceptor      Learner
   |         |          |  |  |  |       |  |
   |         X--------->|->|->|->|       |  |  Any(N,I,Recovery)
   |         |          |  |  |  |       |  |
   X------------------->|->|->|->|       |  |  Accept!(N,I,W)//向全部Server提議,全部Server收到消息後,接受提議
   |         |<---------X--X--X--X------>|->|  Accepted(N,I,W)//向提議人發送接受提議的消息
   |<------------------------------------X--X  Response(W)
   |         |          |  |  |  |       |  |

第一種實現: LeaderElection

LeaderElection是Fast paxos最簡單的一種實現,每一個Server啓動之後都詢問其它的Server它要投票給誰,收到全部Server回覆之後,就計算出zxid最大的哪 個Server,並將這個Server相關信息設置成下一次要投票的Server

 

每一個Server都有一個response線程和選舉線程,咱們先看一下每一個線程是作一些什麼事情

response線程

它主要功能是被動的接受對方法的請求,並根據當前本身的狀態做出相應的回覆,每次回覆都有本身的Id,以及xid,咱們根據他的狀態來看一看他都回復了哪些內容

LOOKING狀態:

本身要推薦的Server相關信息(id,zxid)

LEADING狀態

myid,上一次推薦的Server的id

FLLOWING狀態:

當前Leader的id,以及上一次處理的事務ID(zxid)

選舉線程

選舉線程由當前Server發起選舉的線程擔任,他主要的功能對投票結果進行統計,並選出推薦的Server。選舉線程首先向全部Server發起 一次詢問(包括本身),被詢問方,根據本身當前的狀態做相應的回覆,選舉線程收到回覆後,驗證是不是本身發起的詢問(驗證 xid是否一致),而後獲取對方的id(myid),並存儲到當前詢問對象列表中,最後獲取對方提議的leader相關信息(id,zxid),並將這些 信息存儲到當次選舉的投票記錄表中,當向全部Server都詢問完之後,對統計結果進行篩選並進行統計,計算出當次詢問後獲勝的是哪個 Server,並將當前zxid最大的Server設置爲當前Server要推薦的Server(有多是本身,也有能夠是其它的Server,根據投票 結果而定,可是每個Server在第一次投票時都會投本身),若是此時獲勝的Server得到n/2 + 1的Server票數, 設置當前推薦的leader爲獲勝的Server,將根據獲勝的Server相關信息設置本身的狀態。每個Server都重複以上流程,直到選出 leader

瞭解每一個線程的功能之後,咱們來看一看選舉過程

  • 選舉過程當中,Server的加入

當一個Server啓動時它都會發起一次選舉,此時由選舉線程發起相關流程,那麼每一個Server都會得到當前zxid最大的哪一個Server是 誰,若是當次最大的Server沒有得到n/2+1個票數,那麼下一次投票時,他將向zxid最大的Server投票,重複以上流程,最後必定能選舉出一 個Leader

  • 選舉過程當中,Server的退出

只要保證n/2+1個Server存活就沒有任何問題,若是少於n/2+1個Server存活就沒辦法選出Leader

  • 選舉過程當中,Leader死亡

當選舉出Leader之後,此時每一個Server應該是什麼狀態(FLLOWING)都已經肯定,此時因爲Leader已經死亡咱們就無論它,其它 的Fllower按正常的流程繼續下去,當完成這個流程之後,全部的Fllower都會向Leader發送Ping消息,若是沒法ping通,就改變本身 的狀態爲(FLLOWING ==> LOOKING),發起新的一輪選舉

  • 選舉完成之後,Leader死亡

這個過程的處理跟選舉過程當中Leader死亡處理方式同樣,這裏就再也不描述

第二種實現: FastLeaderElection

fastLeaderElection是標準的fast paxos的實現,它首先向全部Server提議本身要成爲leader,當其它Server收到提議之後,解決epoch和zxid的衝突,並接受對方的提議,而後向對方發送接受提議完成的消息

數據結構

本地消息結構:

static public class Notification {
long leader;  //所推薦的Server id

long zxid;      //所推薦的Server的zxid(zookeeper transtion id)

long epoch;   //描述leader是否變化(每個Server啓動時都有一個logicalclock,初始值爲0)

QuorumPeer.ServerState state;   //發送者當前的狀態
InetSocketAddress addr;            //發送者的ip地址
}

網絡消息結構:

static public class ToSend {

int type;        //消息類型
long leader;  //Server id
long zxid;     //Server的zxid
long epoch;  //Server的epoch
QuorumPeer.ServerState state; //Server的state
long tag;      //消息編號

InetSocketAddress addr;

}

Server具體的實現

每一個Server都一個接收線程池(3個線程)和一個發送線程池 (3個線程),在沒有發起選舉時,這兩個線程池處於阻塞狀態,直到有消息到來時才解除阻塞並處理消息,同時每一個Server都有一個選舉線程(能夠發起 選舉的線程擔任);咱們先看一下每一個線程所作的事情,以下:

被動接收消息端(接收線程池)的處理:

notification: 首先檢測當前Server上所被推薦的zxid,epoch是否合法(currentServer.epoch <= currentMsg.epoch && (currentMsg.zxid > currentServer.zxid || (currentMsg.zxid == currentServer.zxid && currentMsg.id > currentServer.id))) 若是不合法就用消息中的zxid,epoch,id更新當前Server所被推薦的值,此時將收到的消息轉換成Notification消息放入接收隊列 中,將向對方發送ack消息

ack:   將消息編號放入ack隊列中,檢測對方的狀態是不是LOOKING狀態,若是不是說明此時已經有Leader已經被選出來,將接收到的消息轉發成Notification消息放入接收對隊列

主動發送消息端(發送線程池)的處理:

notification: 將要發送的消息由Notification消息轉換成ToSend消息,而後發送對方,並等待對方的回覆,若是在等待結束沒有收到對方法回覆,重作三次, 若是重作次仍是沒有收到對方的回覆時檢測當前的選舉(epoch)是否已經改變,若是沒有改變,將消息再次放入發送隊列中,一直重複直到有Leader選 出或者收到對方回覆爲止

ack: 主要將本身相關信息發送給對方

主動發起選舉端(選舉線程)的處理:

首先本身的epoch 加1,而後生成notification消息,並將消息放入發送隊列中,系統中配置有幾個Server就生成幾條消息,保證每一個Server都能收到此消 息,若是當前Server的狀態是LOOKING就一直循環檢查接收隊列是否有消息,若是有消息,根據消息中對方的狀態進行相應的處理。

LOOKING狀態:

首先檢測消息中epoch是否合法,是否比當前Server的大,若是比較當前Server的epoch大時,更新epoch,檢測是消息中的 zxid,id是否比當前推薦的Server大,若是是更新相關值,並新生成notification消息放入發關隊列,清空投票統計表; 若是消息小的epoch則什麼也不作; 若是相同檢測消息中zxid,id是否合法,若是消息中的zxid,id大,那麼更新當前Server相關信息,並新生成notification消息放 入發送隊列,將收到的消息的IP和投票結果放入統計表中,並計算統計結果,根據結果設置本身相應的狀態

LEADING狀態:

將收到的消息的IP和投票結果放入統計表中(這裏的統計表是獨立的),並計算統計結果,根據結果設置本身相應的狀態

FOLLOWING狀態:

將收到的消息的IP和投票結果放入統計表中(這裏的統計表是獨立的),並計算統計結果,根據結果設置本身相應的狀態

瞭解每一個線程的功能之後,咱們來看一看選舉過程,選舉過程跟第一程同樣

  • 選舉過程當中,Server的加入

當一個Server啓動時它都會發起一次選舉,此時由選舉線程發起相關流程,經過將本身的zxid和epoch告訴其它Server,最後每一個 Server都會得zxid值最大的哪一個Server的相關信息,而且在下一次投票時就投zxid值最大的哪一個Server,重複以上流程,最後必定能選 舉出一個Leader

  • 選舉過程當中,Server的退出

只要保證n/2+1個Server存活就沒有任何問題,若是少於n/2+1個Server存活就沒辦法選出Leader

  • 選舉過程當中,Leader死亡

當選舉出Leader之後,此時每一個Server應該是什麼狀態 (FLLOWING)都已經肯定,此時因爲Leader已經死亡咱們就無論它,其它的Fllower按正常的流程繼續下去,當完成這個流程之後,全部的 Fllower都會向Leader發送Ping消息,若是沒法ping通,就改變本身的狀態爲(FLLOWING ==> LOOKING),發起新的一輪選舉

  • 選舉完成之後,Leader死亡

這個過程的處理跟選舉過 程中Leader死亡處理方式同樣,這裏就再也不描述

相關文章
相關標籤/搜索