Serf使用Gossip Protocol來廣播消息到集羣中。本文介紹這個內部協議的細節。gossip協議基於「SWIM: Scalable Weakly-consistent Infection-style Process Group Membership Protocol」,有一寫小的適配,很大程度上增長了傳播速度和收斂速率。node
Serf以加入一個已存在的集羣或者啓動一個新集羣開始。若是啓動一個新集羣,其餘節點則會加入它。爲了加入現有集羣,新節點必須至少分配一個已經存在的節點的地址。新的成員與現有成員經過TCP作一個完整的狀態同步而且開始gossip它的存在到集羣中。網絡
Gossip基於UDP而且具備一個可配可是固定的扇出(fanout)和間隔。這保證網絡資源使用是固定的,不論節點數有多少。經過TCP隨機的與一個節點週期的進行完整狀態交換,可是遠遠少於gossip消息。全狀態交換和合並會增長成員關係列表收斂的可能性。全狀態交換的間隔是可配的或者徹底中止。性能
故障檢測經過可配間隔的週期性的隨機探測實現。若是節點在一個響應時間內(一般是RTT時間的倍數)沒有進行ack,會嘗試間接探測。間接探測要求可配數量的節點來探測相同的節點,以防網絡問題致使咱們的節點探測失敗。若是咱們的探測和間接探測都在響應時間內失敗,則該節點被標記爲「suspicious」而且會被gossip到集羣中。一個可疑節點仍然視爲集羣的成員。若是集羣的能夠節點在一個可配的週期時間內對懷疑沒有爭論,則節點最終被認爲死亡,這個狀態被gossip到集羣中。排序
這是對協議的一個簡短和不完整的描述。更好的方式是完整閱讀 SWIM論文和Serf的源代碼。事件
如前所述,gossip協議基於SWIM,可是包含小的變化,很大程度上增長了傳播速度和收斂速率。ip
SWIM的變化都記錄在這:ci
SWIM假設本地節點是健康的,也就是說能夠軟實時處理數據包是可能的。然而,在本地節點正在經歷CPU或者網絡資源耗盡的狀況下,這個假設就不成立了。結果是會致使節點健康偶爾振動,致使錯誤的監控報警,增長遙測噪聲,而且直接致使整個集羣浪費CPU和網絡資源來診斷一個可能並不存在的故障。資源
Serf 0.8版本添加了Lifeguard,它徹底解決了這個問題經過加強SWIM。get
第一個擴展是引入了「nack」消息來探測查詢。 If the probing node realizes it is missing "nack" messages then it becomes aware that it may be degraded and slows down its failure detector. As nack messages begin arriving, the failure detector is sped back up.同步
第二個變化是引入了在聲明另外一個結點故障以前動態改變懷疑超時時間的功能。探測結點初始化時有一個很長的懷疑超時。只有集羣中的其餘節點確認一個節點是能夠的,計時器加速。在正常操做期間檢測時間實際上與早期版本的Serf同樣。然而,若是一個節點被退化,而且沒有獲得確認,則會有一個很長的超時時間來容許被懷疑的節點來反駁它的狀態而且保持健康。
這兩個機制聯合使得Serf對於集羣中退化的節點更加健壯,同時保持故障檢測性能不變。Lifeguard沒有額外的配置,它自動調節。
在基於SWIM的gossip層上,Serf發送一些自定義的消息類型。
Serf大量使用Lamport clocks來維護消息的順序,雖然最終是一致的。每一個由Serf發出的消息都包含一個Lamport clock時間。
當一個節點優雅的離開集羣時,Serf經過gossip層發送一個leave intent。由於gossip層如下不區分節點離開集羣和一個節點被檢測爲故障的,這容許更高級別的Serf層來檢測故障與優雅的離開。
當一個節點加入集羣時,Serf發送一個join intent。這個意圖的目的僅僅是綁定一個Lamport clock時間到join上使得在leave亂序來臨時,join能夠被正確的排序。
對於自定義的事件和查詢,Serf發送user event或者user query消息。這個消息包含Lamport時間,事件名稱和事件負載。由於user event是沿着使用UDP的gossip層發送,負載和整個消息幀必須知足在單個UDP包內