本文主要介紹Consul中的重要核心庫——Serf,解釋其概念及做用,可以解決的問題,以及其內部通訊原理。
html
Consul是用於服務發現和配置的工具。它提供了一系列高級功能,例如服務發現、健康檢查和鍵/值存儲。它使用一組高度一致的服務器來管理數據中心。其內部使用的gossip協議是由Serf庫提供支持。Consul使用了Serf的成員管理和故障檢測的機制,並在此基礎上進行高級功能的構建。
web
而Serf主要用於集羣成員管理、故障檢測和編排的工具,它是分佈式、高容錯和高可用的。Serf可以運行在全部主要平臺上:Linux、MacOSX和Windows。它自己是輕量級的,僅使用5-10 MB的常駐內存,並使用UDP消息進行通訊。
服務器
Serf使用gossip協議來解決如下三個問題:網絡
集羣成員管理:Serf維護一個集羣成員列表,並可以在成員更改時執行自定義程序腳本。例如,Serf能夠維護負載均衡器的web服務器列表,並在節點聯機或脫機時通知負載均衡器。app
故障檢測及恢復:Serf能在幾秒鐘內自動檢測失敗的節點,通知集羣內部其餘節點,並執行處理這些事件的程序腳本。它會經過按期從新鏈接失敗的節點來恢復它們。負載均衡
自定義事件傳播:Serf能夠向集羣廣播自定義事件,能夠用來觸發部署、傳播配置等。Serf在面對離線節點或網絡分區時採起最大努力傳遞消息策略。分佈式
Serf還能夠用於服務發現和編排,但它是創建在最終一致性的gossip模型之上的,沒有集中式服務器。但Serf並無提供任何與Consul耦合的高級功能。Serf提供的成員是節點級別的,而Consul則更側重於服務級別的抽象。Consul還使用了強一致的Catalog,而Serf只是最終一致。
ide
Consul還提供了一個鍵/值存儲和對多個數據中心的支持。它利用多個gossip池,保留Serf在LAN上的性能,同時仍然在WAN上使用它來鏈接多個數據中心。
工具
Consul在使用方式上相對固定,而Serf則是一種更加靈活和通用的工具。Consul側重於CP(一致性與分區支持)體系結構,更強調一致性而非可用性。Serf則是一個AP(可用性與分區支持)系統,它犧牲了一致性而強調可用性。這意味着若是中央服務器不能造成有效仲裁,Consul將沒法運行,而Serf將在幾乎全部狀況下良好運行。性能
Serf使用gossip協議向集羣廣播消息。gossip協議是基於「可伸縮的弱一致的感染式進程組成員協議(SWIM協議)」並進行了一些小的修改,主要是爲了提升傳播速度和收斂速度。
Serf從加入現有集羣或啓動新集羣開始。若是啓動一個新的集羣,則須要其餘節點加入它。要加入集羣,必須向現有集羣中的新節點提供至少一個現有成員的地址。新成員經過TCP與現有成員進行徹底的狀態同步,並開始向集羣同步其自身的存在。
gossip是經過UDP完成的,具備可配置但固定的扇出和間隔。這確保了網絡的使用相對於節點數量是恆定的。與隨機節點的完整狀態交換按期經過TCP完成,但比gossip消息要少得多。這增長了成員列表適當收斂的可能性,由於交換和合並了完整狀態。徹底狀態交換之間的間隔是可配置的,也能夠徹底禁用。
故障檢測是經過使用可配置的間隔進行週期性隨機探測來完成的。若是節點未能在合理的時間內ack(一般是RTT的若干倍),則嘗試間接探測。間接探測要求可配置數量的隨機節點探測同一個節點,以防止因爲網絡問題而致使咱們本身的節點探測失敗。
若是探測在合理時間內失敗,那麼節點將被標記爲「可疑」,而且這些信息將被傳播到集羣。可疑節點仍然被認爲是集羣的成員。若是集羣中的可疑成員在一段可配置的時間內沒有對懷疑提出異議,則最終認爲節點已死,而後將此狀態傳播給集羣。
如前所述,gossip協議是基於SWIM的,可是包含了一些小的變化,主要是爲了提升傳播和收斂速度。
Serf按期在TCP上執行徹底的狀態同步,而SWIM只經過gossip傳播更改。雖然二者最終都是一致的,可是Serf可以更快地達到收斂性,並從網絡分區中優雅地恢復。
Serf有一個獨立於故障檢測協議的專用gossip層,而SWIM只在探針/ack消息之上集成gossip消息。Serf使用集成方式捎帶專用的gossip消息。該特性擁有更高的傳輸率(例如每200ms一次)和更慢的故障檢測率(例如每秒一次),從而致使整體更快的收斂速度和數據傳播速度。
Serf會將離線節點的狀態保留一段時間,這樣當請求徹底同步時,請求者也會收到關於離線節點的信息。而SWIM不作徹底同步,因此在得知節點已離線,SWIM會當即刪除離線節點及其狀態信息。因此這一變動將再次幫助集羣更快地收斂。
SWIM假設本地節點是健康的,可是假設本地節點正處於CPU或網絡耗盡的狀況下,可能會致使節點的健康情況會出現問題,致使錯誤的監視警報,並進一步致使整個集羣浪費CPU和網絡資源,從而診斷出可能並不真正存在的故障。Serf 0.8增長了Lifeguard機制來解決這個問題。
第一個擴展是引入了一個「nack」消息來探測查詢。若是探測節點意識到它丟失了「nack」消息,那麼它就會意識到它可能會降級並下降故障檢測器的速度。當nack消息開始到達時,故障檢測器速率則還原。
第二個變動在於將一個節點聲明爲故障節點以前引入動態更改懷疑超時。探測節點將從一個很是長的懷疑超時開始。當集羣中的其餘節點都確認某個節點可疑,計時器就會加速。在正常操做期間,檢測時間實際上與之前版本的Serf相同。可是,若是一個節點降級而且沒有獲得確認,則會有一個很長的超時,容許可疑節點反駁其狀態。
這兩種機制結合在一塊兒,使得Serf對集羣中降級節點的處理更加健壯,同時保持故障檢測性能不變。
在基於SWIM的gossip層的頂部,Serf發送一些自定義消息類型。Serf大量使用Lamport時鐘來維護消息排序的概念,儘管它們最終是一致的。Serf發送的每條消息都包含一個Lamport時鐘時間。當節點優雅地離開集羣時,Serf經過gossip層發送一個leave意圖。因爲底層gossip層不區分離開集羣的節點和被檢測爲失敗的節點,所以容許高級Serf層檢測節點失敗與優雅離開的場景。
當節點加入集羣時,Serf發送鏈接意圖。這個意圖的目的僅僅是將一個Lamport時鐘時間附加到一個鏈接上,以便在節點離開發生故障時能夠正確地對其進行排序。對於自定義事件和查詢,Serf要麼發送用戶事件,要麼發送用戶查詢消息。此消息包含Lamport時間、事件名稱和事件負載。由於用戶事件是使用UDP的gossip層發送的,因此負載和整個消息幀必須依附於一個UDP包。
參考資料:
Serf內部機制介紹:https://www.serf.io/docs/internals/index.html