? ? ? ? 上篇文章我們講解了Redis Cluster中的主要模塊和兩種重定向方式,這篇文章我們來講解一下Redis Cluster的狀態監測和維護。
Redis Cluster狀態監測及維護
? ? ? ? 要講解Redis Cluster中節點的狀態如何維護,我們要先知道Redis Cluster中的節點有哪些狀態,gossip協議是什么以及具體的通訊(心跳)機制。
節點狀態
? ? ? ? Redis Cluster中的每個節點都維護著一份在自己看來當前整個集群的狀態,主要包括:
? ? ? ? (1)當前集群的狀態;
? ? ? ? (2)集群中各節點所負責的Slots信息,及其migrate狀態;
? ? ? ? (3)集群中各節點的Master-Slave狀態;
? ? ? ? (4)集群中各節點的存活狀態及不可達投票。
? ? ? ? 當集群的狀態發生變化時,比如新節點的加入、Slot遷移、節點宕機、新Master的出現等,我們希望這些變化盡快的被發現,傳播到整個集群的所有節點并達成一致。節點之間相互的心跳(PING、PONG、MEET)及其攜帶的數據是集群狀態傳播最主要的途徑。
gossip協議
? ? ? ? gossip協議又稱為epidemic協議,是基于流行病傳播方式的節點或進程之間信息交換的協議。在分布式系統中被廣泛使用,比如我們可以使用gossip協議來確保網絡中所有節點的數據一樣。
? ? ? ? gossip協議已經是P2P網絡中比較成熟的協議了。gossip協議的最大好處是,即使集群節點的數量增加,每個節點的負載也不會增加很多,幾乎是恒定的。這就允許Consul管理的集群規模能橫向擴展到數千個節點。
? ? ? ? Redis集群是去中心化的,彼此之間狀態同步靠gossip協議通信,集群的消息有以下幾種類型:
? ? ? ? (1)Meet:通過cluster meet ip port命令,已有集群的節點會向新的節點發送邀請,加入現有集群。
? ? ? ? (2)Ping:節點每秒會向集群中其他節點發送Ping消息,消息中帶有自己已知的兩個節點的地址、槽、狀態信息、最后一次通信時間等。
? ? ? ? (3)Pong:節點收到Ping消息后會回復Pong消息,消息中同樣帶有自己已知的兩個節點消息。
? ? ? ? (4)Fail:節點Ping不通某節點后,會向集群所有節點廣播該節點掛掉的消息。其他節點收到消息后標記為已下線。????????
? ? ? ? 集群中的每個節點都會定期地向集群中的其他節點發送PING消息,以此交換各個節點狀態信息,檢測各個節點的狀態:在線狀態、疑似下線狀態PFAIL、已下線狀態FAIL。
? ? ? ? 當主節點A通過消息得知主節點B認為主節點D進入疑似下線狀態時,主節點A會在自己的clusterState.nodes字典中找到主節點D所對應的clusterNode結構,并將主節點B的下線報告添加到clusterNode結構的fail_reports鏈表中,并后續關于節點D疑似下線的狀態通過gossip協議通知其他節點。
? ? ? ? 如果集群中,半數以上的主節點都將主節點D報告為下線狀態,那么主節點D就被標記為已下線狀態,將主節點D標記為已下線的節點會向集群廣播主節點D的Fail消息,所有收到Fail消息的節點都會立即更新nodes里面主節點D的狀態,標記為已下線。
? ? ? ? 將node標記為FAIL需要滿足一下兩個條件:①有半數以上的主節點將node標記為PFAIL狀態。②當前節點也將node標記為PFAIL狀態。
通訊狀態和維護
? ? ? ? 什么時候進行心跳?
? ? ? ? Redis節點會記錄其向每一個節點上一次發出ping和收到pong的時間,心跳發送時機與這兩個值有關。通過下面的方式既能保證及時更新集群狀態,又不至于使心跳次數過多:
? ? ? ? (1)每次Cron向所有未建立鏈接的節點發送ping或meet;
? ? ? ? (2)每1秒從所有已知節點中隨機選取5個,向其中上次收到的pong最久遠的一個發送ping。
? ? ? ? (3)每次Cron向收到pong超過timeout/2的節點發送pong;
? ? ? ? (4)收到ping或者meet,立即回復pong。
? ? ? ? 發送哪些心跳數據?
? ? ? ? (1)Header:發送者自己的信息,包括所負責的slots信息、主從信息、ip port信息和狀態信息。
? ? ? ? (2)gossip:發送者所了解的部分其他節點的信息,包括ping_sent,pong_received、ip,port信息、狀態信息(比如發送者認為該節點已經不可達,會在狀態信息中標記其為PFAIL或FAIL)。
? ? ? ? 如何處理心跳數據?
? ? ? ? (1)新節點的加入。發送meet包加入集群,從pong包中的gossip得到未知的其他節點。通過循環上述過程,直到最終加入集群。
? ? ? ? (2)slots信息。判斷發送者聲明的slots信息,跟本地記錄的是否有不同。如果不同,并且發送者epoch較大,更新本地記錄;如果不同,并且發送者epoch比較小,發送update信息通知發送者。
? ? ? ? (3)Master slave信息。發現發送者的master、slave信息變化,更新本地狀態。
? ? ? ? (4)節點FAIL探測(故障發現)。超過超時時間仍然沒有收到pong包的節點會被當前節點標記為PFAIL;PFAIL標記會隨著gossip傳播;每次收到心跳包會檢測其中對其他節點的PFAIL標記,當做對該節點FAIL的投票維護在本機;對某個節點的PFAIL標記達到大多數時,將其變為FAIL標記并廣播FAIL消息。
? ? ? ? gossip的存在使得集群狀態的改變可以更快的達到整個集群。每個心跳包中會包含多個gossip包,那么多少個才是合適的呢,Redis的選擇是N/10,其中N是節點數,這樣可以保證在PFAIL投票的過期時間內,節點可以收到80%機器關于失敗節點的gossip,從而使其順利進入Fail狀態。
? ? ? ? 如何將信息廣播給其它節點?
? ? ? ? 當需要發布一些非常重要需要立即送達的消息時,上述心跳+gossip的方式就顯得捉襟見肘了,這時就需要向所有集群內的機器廣播信息,使用廣播發的場景:
? ? ? ? 節點的Fail信息:當發現某一節點不可達時,探測節點會將其標記為PFAIL狀態,并通過心跳傳播出去。當某一節點發現這個節點的PFAIL超過半數時修改其為FAIL并發起廣播。
? ? ? ? Failover Request信息:slave嘗試發起FailOver時廣播其要求投票的信息。
? ? ? ? 新Master信息:Failover成功的節點向整個集群廣播自己的信息。
故障恢復
? ? ? ? 當slave發現自己的master變為FAIL狀態時,便嘗試進行Failover,以期成為新的Master。由于掛掉的Master可能會有多個Slave。Failover的過程需要經過類Raft協議的過程在整個集群內達到一致,具體的過程如下:
? ? ? ? (1)Slave發現自己的Master變為FAIL;
? ? ? ? (2)將自己記錄的集群currentepoch+1,并廣播Failover Request信息;
? ? ? ? (3)其他節點收到該消息,只有Master響應,判斷請求者的合法性,并發送FAILOVER_AUTH_ACK,對每一個epoch只發送一次ack;
? ? ? ? (4)嘗試Failover的Slave收集FAILOVER_AUTH_ACK;
? ? ? ? (5)超過半數后變為新Master;
? ? ? ? (6)廣播Pong通知其他集群節點。
? ? ? ? 這篇文章我們主要講解了Redis Cluster的狀態監測和維護,大家有什么問題或勘誤可以在評論區留言,筆者看到都會回復的。