Consul探祕:Serf內部通信協議介紹

本文主要介紹Consul中的重要核心庫——Serf,解釋其概念及作用,能夠解決的問題,以及其內部通信原理。



Consul是用於服務發現和配置的工具。它提供了一系列高級功能,例如服務發現、健康檢查和鍵/值存儲。它使用一組高度一致的服務器來管理數據中心。其內部使用的gossip協議是由Serf庫提供支持。Consul使用了Serf的成員管理和故障檢測的機制,並在此基礎上進行高級功能的構建。



Serf主要用於集羣成員管理、故障檢測和編排的工具,它是分佈式、高容錯和高可用的。Serf能夠運行在所有主要平臺上:LinuxMacOSXWindows。它本身是輕量級的,僅使用5-10 MB的常駐內存,並使用UDP消息進行通信。


Serf使用gossip協議來解決以下三個問題:

  • 集羣成員管理:Serf維護一個集羣成員列表,並能夠在成員更改時執行自定義程序腳本。例如,Serf可以維護負載均衡器的web服務器列表,並在節點聯機或脫機時通知負載均衡器。

  • 故障檢測及恢復:Serf能在幾秒鐘內自動檢測失敗的節點,通知集羣內部其他節點,並執行處理這些事件的程序腳本。它會通過定期重新連接失敗的節點來恢復它們。

  • 自定義事件傳播:Serf可以向集羣廣播自定義事件,可以用來觸發部署、傳播配置等。Serf在面對離線節點或網絡分區時採取最大努力傳遞消息策略。


Serf還可以用於服務發現和編排,但它是建立在最終一致性的gossip模型之上的,沒有集中式服務器。但Serf並沒有提供任何與Consul耦合的高級功能。Serf提供的成員是節點級別的,而Consul則更側重於服務級別的抽象。Consul還使用了強一致的Catalog,而Serf只是最終一致。



Consul還提供了一個鍵/值存儲和對多個數據中心的支持。它利用多個gossip池,保留SerfLAN上的性能,同時仍然在WAN上使用它來連接多個數據中心。



Consul在使用方式上相對固定,而Serf則是一種更加靈活和通用的工具。Consul側重於CP(一致性與分區支持)體系結構,更強調一致性而非可用性。Serf則是一個AP(可用性與分區支持)系統,它犧牲了一致性而強調可用性。這意味着如果中央服務器不能形成有效仲裁,Consul將無法運行,而Serf將在幾乎所有情況下良好運行。



Gossip 協議

Serf使用gossip協議向集羣廣播消息。gossip協議是基於“可伸縮的弱一致的感染式進程組成員協議(SWIM協議)”並進行了一些小的修改,主要是爲了提高傳播速度和收斂速度。


SWIM協議概述

Serf從加入現有集羣或啓動新集羣開始。如果啓動一個新的集羣,則需要其他節點加入它。要加入集羣,必須向現有集羣中的新節點提供至少一個現有成員的地址。新成員通過TCP與現有成員進行完全的狀態同步,並開始向集羣同步其自身的存在。



gossip是通過UDP完成的,具有可配置但固定的扇出和間隔。這確保了網絡的使用相對於節點數量是恆定的。與隨機節點的完整狀態交換定期通過TCP完成,但比gossip消息要少得多。這增加了成員列表適當收斂的可能性,因爲交換和合並了完整狀態。完全狀態交換之間的間隔是可配置的,也可以完全禁用。



故障檢測是通過使用可配置的間隔進行週期性隨機探測來完成的。如果節點未能在合理的時間內ack(通常是RTT的若干倍),則嘗試間接探測。間接探測要求可配置數量的隨機節點探測同一個節點,以防止由於網絡問題而導致我們自己的節點探測失敗。



如果探測在合理時間內失敗,那麼節點將被標記爲“可疑”,並且這些信息將被傳播到集羣。可疑節點仍然被認爲是集羣的成員。如果集羣中的可疑成員在一段可配置的時間內沒有對懷疑提出異議,則最終認爲節點已死,然後將此狀態傳播給集羣。


SWIM協議變更

如前所述,gossip協議是基於SWIM的,但是包含了一些小的變化,主要是爲了提高傳播和收斂速度。

  • Serf定期在TCP上執行完全的狀態同步,而SWIM只通過gossip傳播更改。雖然兩者最終都是一致的,但是Serf能夠更快地達到收斂性,並從網絡分區中優雅地恢復。

  • Serf有一個獨立於故障檢測協議的專用gossip層,而SWIM只在探針/ack消息之上集成gossip消息。Serf使用集成方式捎帶專用的gossip消息。該特性擁有更高的傳輸率(例如每200ms一次)和更慢的故障檢測率(例如每秒一次),從而導致總體更快的收斂速度和數據傳播速度。

  • Serf會將離線節點的狀態保留一段時間,這樣當請求完全同步時,請求者也會收到關於離線節點的信息。而SWIM不做完全同步,所以在得知節點已離線,SWIM會立即刪除離線節點及其狀態信息。所以這一變更將再次幫助集羣更快地收斂。


Lifeguard機制

SWIM假設本地節點是健康的,但是假設本地節點正處於CPU或網絡耗盡的情況下,可能會導致節點的健康狀況會出現問題,導致錯誤的監視警報,並進一步導致整個集羣浪費CPU和網絡資源,從而診斷出可能並不真正存在的故障。Serf 0.8增加了Lifeguard機制來解決這個問題。


第一個擴展是引入了一個“nack”消息來探測查詢。如果探測節點意識到它丟失了“nack”消息,那麼它就會意識到它可能會降級並降低故障檢測器的速度。當nack消息開始到達時,故障檢測器速率則還原。


第二個變更在於將一個節點聲明爲故障節點之前引入動態更改懷疑超時。探測節點將從一個非常長的懷疑超時開始。當集羣中的其他節點都確認某個節點可疑,計時器就會加速。在正常操作期間,檢測時間實際上與以前版本的Serf相同。但是,如果一個節點降級並且沒有得到確認,則會有一個很長的超時,允許可疑節點反駁其狀態。

這兩種機制結合在一起,使得Serf對集羣中降級節點的處理更加健壯,同時保持故障檢測性能不變。


Serf-Specific消息

在基於SWIMgossip層的頂部,Serf發送一些自定義消息類型。Serf大量使用Lamport時鐘來維護消息排序的概念,儘管它們最終是一致的。Serf發送的每條消息都包含一個Lamport時鐘時間。當節點優雅地離開集羣時,Serf通過gossip層發送一個leave意圖。由於底層gossip層不區分離開集羣的節點和被檢測爲失敗的節點,因此允許高級Serf層檢測節點失敗與優雅離開的場景。


當節點加入集羣時,Serf發送連接意圖。這個意圖的目的僅僅是將一個Lamport時鐘時間附加到一個連接上,以便在節點離開發生故障時可以正確地對其進行排序。對於自定義事件和查詢,Serf要麼發送用戶事件,要麼發送用戶查詢消息。此消息包含Lamport時間、事件名稱和事件負載。因爲用戶事件是使用UDPgossip層發送的,所以負載和整個消息幀必須依附於一個UDP包。


參考資料:

Serf內部機制介紹:https://www.serf.io/docs/internals/index.html

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章