Redis集羣(一)

1、簡介  

  • redis是一個開源的key value存儲系統,受到了廣大互聯網公司的青睞。redis3.0版本以前只支持單例模式,在3.0版本及之後才支持集羣,我這裏用的是redis3.0.0版本;
  • redis集羣採用P2P模式,是徹底去中心化的,不存在中心節點或者代理節點;
  • redis集羣是沒有統一的入口的,客戶端(client)鏈接集羣的時候鏈接集羣中的任意節點(node)便可,集羣內部的節點是相互通訊的(PING-PONG機制),每一個節點都是一個redis實例;
  • 爲了實現集羣的高可用,即判斷節點是否健康(可否正常使用),redis-cluster有這麼一個投票容錯機制:若是集羣中超過半數的節點投票認爲某個節點掛了,那麼這個節點就掛了(fail)。這是判斷節點是否掛了的方法;
  • 那麼如何判斷集羣是否掛了呢? -> 若是集羣中任意一個節點掛了,並且該節點沒有從節點(備份節點),那麼這個集羣就掛了。這是判斷集羣是否掛了的方法;
  • 那麼爲何任意一個節點掛了(沒有從節點)這個集羣就掛了呢? -> 由於集羣內置了16384個slot(哈希槽),而且把全部的物理節點映射到了這16384[0-16383]個slot上,或者說把這些slot均等的分配給了各個節點。當須要在Redis集羣存放一個數據(key-value)時,redis會先對這個key進行crc16算法,而後獲得一個結果。再把這個結果對16384進行求餘,這個餘數會對應[0-16383]其中一個槽,進而決定key-value存儲到哪一個節點中。因此一旦某個節點掛了,該節點對應的slot就沒法使用,那麼就會致使集羣沒法正常工做。
  • 綜上所述,每一個Redis集羣理論上最多能夠有16384個節點。

2、三種集羣模型

  一、主從模型

  在主從複製中,數據庫分爲兩類:主數據庫(master)和從數據庫(slave)。node

  當slave啓動後,主動向master發送SYNC命令。master接收到SYNC命令後在後臺保存快照(RDB持久化)和緩存保存快照這段時間的命令,而後將保存的快照文件和緩存的命令發送給slave。slave接收到快照文件和命令後加載快照文件和緩存的執行命令。redis

  爲了在主節點子集發生故障或沒法與大多數節點通訊時保持可用,Redis Cluster使用主從模型,其中每一個哈希槽具備從1(主節點自己)到N個副本(N個) -1個其餘從屬節點)。在具備節點A,B,C的示例集羣中,若是節點B失敗,則集羣將沒法繼續,由於咱們再也不有辦法爲5501-11000範圍內的哈希槽提供服務。算法

  可是,在建立集羣(或稍後)時,咱們向每一個主節點添加一個從屬節點,以便最終集羣由做爲主節點的A,B,C和做爲從屬節點的A1,B1,C1組成,若是節點B發生故障,系統將可以繼續。數據庫

  節點B1複製B,而且B發生故障,羣集會將節點B1提高爲新的主節點,並將繼續正常運行。緩存

  可是請注意,若是節點B和B1同時失敗,則Redis Cluster沒法繼續運行。安全

  解決問題:服務器

    解決Redis單例下,數據體量大與數據備份形成的性能瓶頸問題,redis cluster 主從模型很好的解決這個問題。能夠將讀寫操做分離到不一樣redis實例上,提升系統的吞吐量    網絡

  引入新的問題:併發

    一、配置重連問題dom

      不一樣的redis實例,須要不一樣的ip和端口對應,若是某個實例下線了,須要從新更改配置進行重連

    二、故障轉移問題

      若是某個結點故障下線,沒法進行故障轉移,好比某個master下線,對應的slave結點也只能進行讀操做,沒法進行寫操做,替代不了master的功能。

  特色以下:

  • 主數據庫能夠進行讀寫操做,當讀寫操做致使數據變化時會自動將數據同步給從數據庫
  • 從數據庫通常都是隻讀的,而且接收主數據庫同步過來的數據
  •  一個master能夠擁有多個slave,可是一個slave只能對應一個master
  • slave掛了不影響其餘slave的讀和master的讀和寫,從新啓動後會將數據從master同步過來
  • master掛了之後,不影響slave的讀,但redis再也不提供寫服務,master重啓後redis將從新對外提供寫服務
  • master掛了之後,不會在slave節點中從新選一個master

  缺點以下:

  master節點在主從模式中惟一,若master掛掉,則redis沒法對外提供寫服務,不具有高可用性。

  二、哨兵模型

Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance)。

監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。 

提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。

自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會進行選舉,將其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主服務器代替失效服務器。

解決問題:  

    Sentinel哨兵模式,確實實現自動故障切換。提供穩定的服務,解決主從模型引入的新問題。 

  未解決的問題:

    在哨兵模式中,仍然只有一個Master節點。當併發寫請求較大時,哨兵模式並不能緩解寫壓力。

  特色以下:

  • Sentinel能夠監控任意多個Master和該Master下的Slaves。(即多個主從模式) 
  • 同一個哨兵下的、不一樣主從模型,彼此之間相互獨立。
  • Sentinel會不斷檢查Master和Slaves是否正常。
  • 監控同一個Master的Sentinel會自動鏈接,組成一個分佈式的Sentinel網絡,互相通訊並交換彼此關於被監視服務器的信息,在sentinel網絡中,只要還有一個sentinel活着,就能夠實現故障切換。當只有一個sentinel的時候,若是這個sentinel掛掉了,那麼就沒法實現自動故障切換了。
  • 故障轉移:投票(半數原則),當任何一個Sentinel發現被監控的Master下線時,會通知其它的Sentinel開會,投票肯定該Master是否下線(半數以上,因此sentinel一般配奇數個)。
  • 故障轉移:選舉,當Sentinel肯定Master下線後,會在全部的Slaves中,選舉一個新的節點,升級成Master節點。其它Slaves節點,轉爲該節點的從節點。 
  • 原Master從新上線,當原Master節點從新上線後,自動轉爲當前Master節點的從節點。

  三、Redis cluster 集羣 

   Redis 3.0 以後版本支持 Redis Cluster 集羣,Redis Cluster採用無中心結構,每一個節點保存數據和整個集羣狀態,每一個節點都和其餘全部節點鏈接。 

     目標:  

  • 高達1000個節點的高性能和線性可擴展性。沒有代理,使用異步複製,而且不對值執行合併操做。
  • 可接受的寫安全程度:系統嘗試(以盡力而爲的方式)保留全部來自與大多數主節點鏈接的客戶端的寫操做。一般,有一些小窗口,在這些小窗口中,可能會丟失已確認的寫入。當客戶端位於少數分區中時,丟失已確認寫入的Windows更大。
  • 可用性:Redis Cluster可以在大多數主節點可訪問且每一個再也不可用的主節點上至少有一個可訪問的從節點的分區中生存。並且,經過使用副本遷移,再也不由任何從屬複製的主將從一個由多個從屬覆蓋的主接收一個。

    高性能:

  • 採用了異步複製機制,向某個節點寫入數據時,無需等待其它節點的寫數據響應。
  • 無中心代理節點,而是將客戶端直接重定向到擁有數據的節點。
  • 對於N個 Master 節點的 Cluster ,總體性能理論上至關於單個 Redis 的性能的N倍。

    高可用:

    採用了主從複製的機制,Master 節點失效時 Slave 節點自動提高爲 Master 節點。若是 Cluster 中有N個 Master 節點,每一個 Master 擁有1個 Slave 節點,那麼這個   Cluster 的失效機率爲 1/(2*N-1),可用機率爲 1-1/(2*N-1)。

    高可擴展:

    可支持多達1000個服務節點。隨時能夠向 Cluster 中添加新節點,或者刪除現有節點。Cluster 中每一個節點都與其它節點創建了相互鏈接

    一致性:  

  Redis Cluster沒法保證強一致性實際上,這意味着在某些狀況下,Redis Cluster可能會丟失系統承認給客戶端的寫入。

Redis Cluster可能丟失寫入的第一個緣由是由於它使用異步複製。這意味着在寫入期間會發生如下狀況:

    • 您的客戶寫信給主B。
    • 主B向您的客戶答覆「肯定」。
    • 主機B將寫操做傳播到其從機B1,B2和B3。

  B在回覆客戶端以前不會等待B1,B2,B3的確認,由於這會對Redis形成延遲性的延遲,所以,若是您的客戶端寫了一些東西,B會確認寫,可是在崩潰以前崩潰因爲可以將寫操做發送到其從屬服務器,所以一個從屬服務器(未接收到寫操做)能夠升級爲主服務器,從而永遠丟失該寫操做。

  特色以下:

  • 全部的 Redis 節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。
  • 節點的fail是經過集羣中超過半數的節點檢測失效時才生效。
  • 客戶端與 Redis 節點直連,不須要中間Proxy層,客戶端不須要鏈接集羣全部節點,鏈接集羣中任何一個可用節點便可。
  • Redis Cluster 把全部的物理節點映射到[0-16383] slot(哈希槽) 上(不必定是平均分配),Cluster 負責維護node <-> slot <-> value。
  • Redis 集羣預分好 16384 個哈希槽,當須要在 Redis 集羣中放置一個 key-value 時,根據 CRC16(key) mod 16384 的值,決定將一個 key 放到哪一個桶中。

3、集羣主要組件 

一、密鑰分配模型 

  密鑰空間被劃分爲16384個插槽,有效地設置了16384個主節點的羣集大小的上限(可是建議的最大節點大小約爲1000個節點)。

  羣集中的每一個主節點都處理16384個哈希槽的子集。當沒有正在進行的集羣從新配置時(即哈希槽從一個節點移動到另外一個節點),該集羣是穩定的。當羣集穩定時,單個哈希槽將由單個節點提供服務(可是,服務節點能夠具備一個或多個從屬設備,在發生網絡分裂或故障的狀況下能夠替換該從屬設備,而且能夠用於擴展)可接受過期數據的讀取操做)。

  鍵映射到哈希槽的基本算法HASH_SLOT = CRC16(key) mod 16384

二、鍵哈希標籤 

  哈希標籤是一種確保在同一哈希槽中分配多個密鑰的方法。這用於在Redis Cluster中實現多鍵操做。 

  爲了實現哈希標籤,在某些狀況下,密鑰的哈希槽以略有不一樣的方式計算。若是密鑰包含一個「{...}」圖案僅之間子 {},以得到散列時隙被散列。可是,因爲可能存在屢次出現{}算法由如下規則很好地指定: 

    • 若是鍵包含一個{字符。
    • 若是有一個}字符的右{
    • AND若是在的第一次出現{和的第一次出現之間存在一個或多個字符}

三、集羣節點屬性 

  每一個節點在集羣中都有惟一的名稱。節點名稱是160位隨機數的十六進制表示形式,是在節點首次啓動時得到的(一般使用/ dev / urandom)。節點將其ID保存在節點配置文件中,並將永久使用相同的ID,或者至少在系統管理員未刪除節點配置文件或經過CLUSTER RESET命令請求硬重置的狀況下使用該ID  

  節點ID用於標識整個集羣中的每一個節點。給定節點能夠更改其IP地址,而無需也更改節點ID。羣集還可以檢測IP /端口的更改,並使用在羣集總線上運行的八卦協議進行從新配置。 

  節點ID並非與每一個節點關聯的惟一信息,而是惟一始終全局一致的信息。每一個節點還具備如下關聯的信息集。一些信息與該特定節點的集羣配置詳細信息有關,而且最終在整個集羣中保持一致。某些其餘信息(例如上次對節點執行ping操做)則是每一個節點本地的。 

  每一個節點都維護着有關羣集中其餘節點的如下信息:節點ID,節點的IP和端口,一組標誌,若是將節點標誌爲slave則該節點的主節點是什麼?對節點執行ping操做,最後一次接收到pong時,將顯示該節點的當前 配置時期(在本規範的後面部分進行說明),連接狀態以及最終服務的哈希槽集。 

四、集羣總線 

  每一個Redis Cluster節點都有一個額外的TCP端口,用於接收來自其餘Redis Cluster節點的傳入鏈接。此端口與用於從客戶端接收傳入鏈接的普通TCP端口處於固定偏移量。要得到Redis Cluster端口,應在常規命令端口中添加10000。例如,若是Redis節點正在端口6379上偵聽客戶端鏈接,則羣集總線端口16379也將打開。

  節點到節點的通訊僅使用羣集總線和羣集總線協議進行:羣集協議是由不一樣類型和大小的幀組成的二進制協議。未公開記錄集羣總線二進制協議,由於它不打算供外部軟件設備使用該協議與Redis Cluster節點通訊。可是,您能夠經過閱讀Redis Cluster源代碼中cluster.hcluster.c文件來獲取有關集羣總線協議的更多詳細信息  

五、集羣拓撲

  Redis Cluster是一個完整的網格,其中每一個節點都使用TCP鏈接與其餘每一個節點鏈接。 

  在N個節點的羣集中,每一個節點都有N-1個傳出TCP鏈接和N-1個傳入鏈接。 

  這些TCP鏈接始終保持活動狀態,而且不會按需建立。當節點但願對集羣總線中的ping作出迴應時,會在等待足夠長的時間以將節點標記爲不可訪問以前進行Pong響應,它將嘗試經過從頭開始從新鏈接來刷新與該節點的鏈接。 

  雖然Redis Cluster節點造成一個完整的網格,可是節點使用八卦協議和配置更新機制以免在正常狀況下在節點之間交換太多消息,所以交換的消息數量不是指數級的。 

六、節點握手

  節點始終接受羣集總線端口上的鏈接,即便收到ping節點不受信任,甚至會在收到ping時回覆ping。可是,若是不將發送節點視爲羣集的一部分,則接收節點將丟棄全部其餘數據包。 

一個節點僅以兩種方式將另外一個節點做爲羣集的一部分:

    • 節點是否向其顯示MEET消息。Meet消息PING消息徹底同樣,可是會強制接收者接受該節點做爲羣集的一部分。只有系統管理員經過如下命令請求節點時,節點纔會將MEET消息發送到其餘節點

      羣集會議IP端口

    • 若是已經受信任的節點將閒聊該節點,則該節點還將另外一個節點註冊爲羣集的一部分。所以,若是A知道B,B知道C,則最終B會向A發送有關C的八卦消息。發生這種狀況時,A會將C註冊爲網絡的一部分,並嘗試與C鏈接。

這意味着只要咱們在任何鏈接圖中加入節點,它們最終將自動造成徹底鏈接圖。這意味着羣集可以自動發現其餘節點,但前提是存在系統管理員強制創建的信任關係。

這種機制使羣集更加健壯,但能夠防止更改IP地址或其餘與網絡相關的事件後,不一樣的Redis羣集意外混合。        

參考連接:

  官網:https://redis.io/topics/cluster-spec 集羣規範

相關文章
相關標籤/搜索