本文首發於: 淺談集羣版Redis和Gossip協議
微信公衆號:後端技術指南針
昨天的文章寫了關於分佈式系統中一致性哈希算法的問題,文末提了一下Redis-Cluster對於一致性哈希算法的實現方案,今天來看一下Redis-Cluster和其中的重要概念Gossip協議。html
1.Redis Cluster的基本概念node
集羣版的Redis聽起來很高大上,確實相比單實例一主一從或者一主多從模式來講複雜了許多,互聯網的架構老是隨着業務的發展不斷演進的。git
最開始的一主N從加上讀寫分離,Redis做爲緩存單實例貌似也還不錯,而且有Sentinel哨兵機制,能夠實現主從故障遷移。github
單實例一主兩從+讀寫分離結構:redis
注:圖片來自網絡算法
單實例的因爲本質上只有一臺Master做爲存儲,就算機器爲128GB的內存,通常建議使用率也不要超過70%-80%,因此最多使用100GB數據就已經不少了,實際中50%就不錯了,覺得數據量太大也會下降服務的穩定性,由於數據量太大意味着持久化成本高,可能嚴重阻塞服務,甚至最終切主。後端
若是單實例只做爲緩存使用,那麼除了在服務故障或者阻塞時會出現緩存擊穿問題,可能會有不少請求一塊兒搞死MySQL。緩存
若是單實例做爲主存,那麼問題就比較大了,由於涉及到持久化問題,不管是bgsave仍是aof都會形成刷盤阻塞,此時形成服務請求成功率降低,這個並非單實例能夠解決的,由於因爲做爲主存儲,持久化是必須的。服務器
因此咱們期待一個多主多從的Redis系統,這樣不管做爲主存仍是做爲緩存,壓力和穩定性都會提高,儘管如此,筆者仍是建議:微信
若是你獨斷獨行,那麼要麼坑了本身,要麼坑了別人。
要支持集羣首先要克服的就是分片問題,也就是一致性哈希問題,常見的方案有三種:
這種狀況主要是相似於哈希取模的作法,當客戶端對服務端的數量徹底掌握和控制時,能夠簡單使用。
這種狀況是在客戶端和服務器端之間增長中間層,充當管理者和調度者,客戶端的請求打向中間層,由中間層實現請求的轉發和回收,固然中間層最重要的做用是對多臺服務器的動態管理。
不使用中間層實現去中心化的管理模式,客戶端直接向服務器中任意結點請求,若是被請求的Node沒有所需數據,則像客戶端回覆MOVED,並告訴客戶端所需數據的存儲位置,這個過程其實是客戶端和服務端共同配合,進行請求重定向來完成的。
前面提到了變爲N主N從能夠有效提升處理能力和穩定性,可是這樣就面臨一致性哈希的問題,也就是動態擴縮容時的數據問題。
在Redis官方發佈集羣版本以前,業內有一些方案火燒眉毛要用起自研版本的Redis集羣,其中包括國內豌豆莢的Codis、國外Twiter的twemproxy。
核心思想都是在多個Redis服務器和客戶端Client中間增長分片層,由分片層來完成數據的一致性哈希和分片問題,每一家的作法有必定的區別,可是要解決的核心問題都是多臺Redis場景下的擴縮容、故障轉移、數據完整性、數據一致性、請求處理延時等問題。
業內Codis配合LVS等多種作法實現Redis集羣的方案有不少都應用到生成環境中,表現都還不錯,主要是官方集羣版本在Redis3.0纔出現,對其穩定性如何,不少公司都不肯作小白鼠,不過事實上通過迭代目前已經到了Redis5.x版本,官方集羣版本仍是很不錯的,至少筆者這麼認爲。
官方版本區別於上面的Codis和Twemproxy,實現了服務器層的Sharding分片技術,換句話說官方沒有中間層,而是多個服務結點自己實現了分片,固然也能夠認爲實現sharding的這部分功能被融合到了Redis服務自己中,並無單獨的Sharding模塊。
以前的文章也提到了官方集羣引入slot的概念進行數據分片,以後將數據slot分配到多個Master結點,Master結點再配置N個從結點,從而組成了多實例sharding版本的官方集羣架構。
Redis Cluster 是一個能夠在多個 Redis 節點之間進行數據共享的分佈式集羣,在服務端,經過節點之間的特殊協議進行通信,這個特殊協議就充當了中間層的管理部分的通訊協議,這個協議稱做Gossip流言協議。
分佈式系統一致性協議的目的就是爲了解決集羣中多結點狀態通知的問題,是管理集羣的基礎。
如圖展現了基於Gossip協議的官方集羣架構圖:
注:圖片來自網絡
2.Redis Cluster的基本運行原理
Cluster中的每一個節點都維護一份在本身看來當前整個集羣的狀態,主要包括:
也就是說上面的信息,就是集羣中Node相互八卦傳播流言蜚語的內容主題,並且比較全面,既有本身的更有別人的,這麼一來你們都相互傳,最終信息就全面並且準確了,區別於拜占庭帝國問題,信息的可信度很高。
基於Gossip協議當集羣狀態變化時,如新節點加入、slot遷移、節點宕機、slave提高爲新Master,咱們但願這些變化儘快的被發現,傳播到整個集羣的全部節點並達成一致。節點之間相互的心跳(PING,PONG,MEET)及其攜帶的數據是集羣狀態傳播最主要的途徑。
gossip 協議(gossip protocol)又稱 epidemic 協議(epidemic protocol),是基於流行病傳播方式的節點或者進程之間信息交換的協議。
在分佈式系統中被普遍使用,好比咱們可使用 gossip 協議來確保網絡中全部節點的數據同樣。
gossip protocol 最初是由施樂公司帕洛阿爾託研究中心(Palo Alto Research Center)的研究員艾倫·德默斯(Alan Demers)於1987年創造的。 www.iteblog.com/archives/25…
Gossip協議已是P2P網絡中比較成熟的協議了。Gossip協議的最大的好處是,即便集羣節點的數量增長,每一個節點的負載也不會增長不少,幾乎是恆定的。這就容許Consul管理的集羣規模能橫向擴展到數千個節點。
Gossip算法又被稱爲反熵(Anti-Entropy),熵是物理學上的一個概念,表明雜亂無章,而反熵就是在雜亂無章中尋求一致,這充分說明了Gossip的特色:在一個有界網絡中,每一個節點都隨機地與其餘節點通訊,通過一番雜亂無章的通訊,最終全部節點的狀態都會達成一致。每一個節點可能知道全部其餘節點,也可能僅知道幾個鄰居節點,只要這些節能夠經過網絡連通,最終他們的狀態都是一致的,固然這也是疫情傳播的特色。 www.backendcloud.cn/2017/11/12/…
上面的描述都比較學術,其實Gossip協議對於咱們吃瓜羣衆來講一點也不陌生,Gossip協議也成爲流言協議,說白了就是八卦協議,這種傳播規模和傳播速度都是很是快的,你能夠體會一下。因此計算機中的不少算法都是源自生活,而又高於生活的。
Redis 集羣是去中心化的,彼此之間狀態同步靠 gossip 協議通訊,集羣的消息有如下幾種類型:
因爲去中心化和通訊機制,Redis Cluster 選擇了最終一致性和基本可用。
例如當加入新節點時(meet),只有邀請節點和被邀請節點知道這件事,其他節點要等待 ping 消息一層一層擴散。除了 Fail 是當即全網通知的,其餘諸如新節點、節點重上線、從節點選舉成爲主節點、槽變化等,都須要等待被通知到,也就是Gossip協議是最終一致性的協議。
因爲 gossip 協議對服務器時間的要求較高,不然時間戳不許確會影響節點判斷消息的有效性。另外節點數量增多後的網絡開銷也會對服務器產生壓力,同時結點數太多,意味着達到最終一致性的時間也相對變長,所以官方推薦最大節點數爲1000左右。如圖展現了新加入結點服務器時的通訊交互圖:
注:圖片來自網絡
總起來講Redis官方集羣是一個去中心化的類P2P網絡,P2P早些年很是流行,像電驢、BT什麼的都是P2P網絡。在Redis集羣中Gossip協議充當了去中心化的通訊協議的角色,依據制定的通訊規則來實現整個集羣的無中心管理節點的自治行爲。
集羣中的每一個節點都會按期地向集羣中的其餘節點發送PING消息,以此交換各個節點狀態信息,檢測各個節點狀態:在線狀態、疑似下線狀態PFAIL、已下線狀態FAIL。
本身保存信息:當主節點A經過消息得知主節點B認爲主節點D進入了疑似下線(PFAIL)狀態時,主節點A會在本身的clusterState.nodes字典中找到主節點D所對應的clusterNode結構,並將主節點B的下線報告添加到clusterNode結構的fail_reports鏈表中,並後續關於結點D疑似下線的狀態經過Gossip協議通知其餘節點。
一塊兒裁定:若是集羣裏面,半數以上的主節點都將主節點D報告爲疑似下線,那麼主節點D將被標記爲已下線(FAIL)狀態,將主節點D標記爲已下線的節點會向集羣廣播主節點D的FAIL消息,全部收到FAIL消息的節點都會當即更新nodes裏面主節點D狀態標記爲已下線。
最終裁定:將 node 標記爲 FAIL 須要知足如下兩個條件:
也就是說當前節點發現其餘結點疑似掛掉了,那麼就寫在本身的小本本上,等着通知給其餘好基友,讓他們本身也看看,最後又一半以上的好基友都認爲那個節點掛了,而且那個節點本身也認爲本身掛了,那麼就是真的掛了,過程仍是比較嚴謹的。
3.參考資料
點贊在看 養成習慣
熱愛生活的你我 都比昨天更優秀!
歡迎關注 微信公衆號:後端技術指南針