宕機後,Redis如何實現快速恢復?

Redis做爲很是火熱的內存數據庫,其除了具備很是高的性能以外,還須要保證高可用,在故障發生時,儘量地下降故障帶來的影響,Redis也提供了完善的故障恢復機制:哨兵。java

下面就來具體來看看Redis的故障恢復是如何作的,以及其中的原理。程序員

部署模式

Redis在部署時,能夠採用多種方式部署,每種部署方式對應不一樣的可用級別。算法

  • 單節點部署:只有一個節點提供服務,讀寫均在此節點,此節點宕機則數據所有丟失,直接影響業務。數據庫

  • master-slave方式部署:兩個節點組成master-slave模式,在master上寫入,slave上讀取,讀寫分離提升訪問性能,master宕機後,須要手動把slave提高爲master,業務影響程度取決於手動提高master的延遲。網絡

  • master-slave+哨兵方式部署:master-slave與上述相同,不一樣的是增長一組哨兵節點,用於實時檢查master的健康狀態,在master宕機後自動提高slave爲新的master,最大程度下降不可用的時間,對業務影響時間較短。app

從上面幾種部署模式能夠看出,提升Redis可用性的關鍵是:多副本部署 + 自動故障恢復,而多副本正是依賴主從複製。分佈式

高可用作法

Redis原生提供master-slave數據複製,保證slave永遠與master數據保持一致。ide

在master發生問題時,咱們須要把slave提高爲master,繼續提供服務。而這個提高新master的操做,若是是人工處理,必然沒法保證及時性,因此Redis提供了哨兵節點,用來管理master-slave節點,並在master發生問題時,可以自動進行故障恢復操做。工具

整個故障恢復的工做,正是Redis哨兵自動完成的。性能

哨兵介紹

哨兵是Redis高可用的解決方案,它是一個管理多個Redis實例的服務工具,能夠實現對Redis實例的監控、通知、自動故障轉移。

在部署哨兵時,咱們只須要在配置文件中配置須要管理的master節點,哨兵節點就能夠根據配置,對Redis節點進行管理,實現高可用。

b89bcd52-d232-476f-b362-0ea7f679fff9


通常咱們須要部署多個哨兵節點,這是由於在分佈式場景下,要想肯定某個機器的某個節點上否發生故障,只用一臺機器去檢測多是不許確的,頗有可能這兩臺機器的網絡發生了故障,而節點自己並無問題。

因此對於節點健康檢測的場景,通常都會採用多個節點同時去檢測,且多個節點分佈在不一樣機器上,節點數量爲奇數個,避免由於網絡分區致使哨兵決策錯誤。這樣多個哨兵節點互相交換檢測信息,最終決策才能確認某個節點上否真正發生了問題。

哨兵節點部署並配置完成後,哨兵就會自動地對配置的master-slave進行管理,在master發生故障時,及時地提高slave爲新的master,保證可用性。

那麼它的工做原理上怎樣的呢?

哨兵工做原理

哨兵的工做流程主要分爲如下幾個階段:

  • 狀態感知

  • 心跳檢測

  • 選舉哨兵領導者

  • 選擇新的master

  • 故障恢復

  • 客戶端感知新master

下面對這些階段進行詳細的介紹。

狀態感知

哨兵啓動後只指定了master的地址,哨兵要想在master故障時進行故障恢復,就須要知道每一個master對應的slave信息。每一個master可能不止一個slave,所以哨兵須要知道整個集羣中完整的的拓撲關係,如何拿到這些信息?

哨兵每隔10秒會向每一個master節點發送info命令,info命令返回的信息中,包含了主從拓撲關係,其中包括每一個slave的地址和端口號。有了這些信息後,哨兵就會記住這些節點的拓撲信息,在後續發生故障時,選擇合適的slave節點進行故障恢復。

哨兵除了向master發送info以外,還會向每一個master節點特殊的pubsub中發送master當前的狀態信息和哨兵自身的信息,其餘哨兵節點經過訂閱這個pubsub,就能夠拿到每一個哨兵發來的信息。

這麼作的目的主要有2個:

  • 哨兵節點能夠發現其餘哨兵的加入,進而方便多個哨兵節點通訊,爲後續共同協商提供基礎

  • 與其餘哨兵節點交換master的狀態信息,爲後續判斷master是否故障提供依據

心跳檢測

在故障發生時,須要當即啓動故障恢復機制,那麼如何保證及時性呢?

每一個哨兵節點每隔1秒向master、slave、其餘哨兵節點發送ping命令,若是對方能在指定時間內響應,說明節點健康存活。若是未在規定時間內(可配置)響應,那麼該哨兵節點認爲此節點主觀下線。

爲何叫作主觀下線?

由於當前哨兵節點探測對方沒有獲得響應,頗有可能這兩個機器之間的網絡發生了故障,而master節點自己沒有任何問題,此時就認爲master故障是不正確的。

要想確認master節點是否真正發生故障,就須要多個哨兵節點共同確認才行。

每一個哨兵節點經過向其餘哨兵節點詢問此master的狀態,來共同確認此節點上否真正故障。

若是超過指定數量(可配置)的哨兵節點都認爲此節點主觀下線,那麼纔會把這個節點標記爲客觀下線。

選舉哨兵領導者

確認這個節點真正故障後,就須要進入到故障恢復階段。如何進行故障恢復,也須要經歷一系列流程。

首先須要選舉出一個哨兵領導者,由這個專門的哨兵領導者來進行故障恢復操做,不用多個哨兵都參與故障恢復。選舉哨兵領導者的過程,須要多個哨兵節點共同協商來選出。

這個選舉協商的過程,在分佈式領域中叫作達成共識,協商的算法叫作共識算法。

共識算法主要爲了解決在分佈式場景下,多個節點如何針對某一個場景達成一致的結果。

共識算法包括不少種,例如Paxos、Raft、Gossip算法等,感興趣的同窗能夠自行搜索相關資料,這裏再也不展開來說。

哨兵選舉領導者的過程相似於Raft算法,它的算法足夠簡單易理解。

簡單來說流程以下:

  • 每一個哨兵都設置一個隨機超時時間,超時後向其餘哨兵發送申請成爲領導者的請求

  • 其餘哨兵只能對收到的第一個請求進行回覆確認

  • 首先達到多數確認選票的哨兵節點,成爲領導者

  • 若是在確認回覆後,全部哨兵都沒法達到多數選票的結果,那麼進行從新選舉,直到選出領導者爲止

選擇出哨兵領導者後,以後的故障恢復操做都由這個哨兵領導者進行操做。

選擇新的master

哨兵領導者針對發生故障的master節點,須要在它的slave節點中,選擇一個節點來代替其工做。

這個選擇新master過程也是有優先級的,在多個slave的場景下,優先級按照:slave-priority配置 > 數據完整性 > runid較小者進行選擇。

也就是說優先選擇slave-priority最小值的slave節點,若是全部slave此配置相同,那麼選擇數據最完整的slave節點,若是數據也同樣,最後選擇runid較小的slave節點。

提高新的master

通過優先級選擇,選出了備選的master節點後,下一步就是要進行真正的主從切換了。

哨兵領導者給備選的master節點發送slaveof no one命令,讓該節點成爲master。

以後,哨兵領導者會給故障節點的全部slave發送slaveof $newmaster命令,讓這些slave成爲新master的從節點,開始重新的master上同步數據。

最後哨兵領導者把故障節點降級爲slave,並寫入到本身的配置文件中,待這個故障節點恢復後,則自動成爲新master節點的slave。

至此,整個故障切換完成。

客戶端感知新master

最後,客戶端如何拿到最新的master地址呢?

哨兵在故障切換完成以後,會向自身節點的指定pubsub中寫入一條信息,客戶端能夠訂閱這個pubsub來感知master的變化通知。咱們的客戶端也能夠經過在哨兵節點主動查詢當前最新的master,來拿到最新的master地址。

另外,哨兵還提供了「鉤子」機制,咱們也能夠在哨兵配置文件中配置一些腳本邏輯,在故障切換完成時,觸發「鉤子」邏輯,通知客戶端發生了切換,讓客戶端從新在哨兵上獲取最新的master地址。

通常來講,推薦採用第一種方式進行處理,不少客戶端SDK中已經集成好了從哨兵節點獲取最新master的方法,咱們直接使用便可。

總結

可見,爲了保證Redis的高可用,哨兵節點要準確無誤地判斷故障的發生,而且快速的選出新的節點來代替其提供服務,這中間的流程仍是比較複雜的。

中間涉及到了分佈式共識、分佈式協商等知識,目的都是爲了保證故障切換的準確性。

咱們有必要了解Redis高可用的工做原理,這樣咱們在使用Redis時能更準確地使用它。

最後

感謝你們看到這裏,若是本文有什麼不足之處,歡迎多多指教;若是你以爲對你有幫助,請給我點個贊。

也歡迎你們關注個人公衆號:程序員麥冬,麥冬天天都會分享java相關技術文章或行業資訊,歡迎你們關注和轉發文章!

相關文章
相關標籤/搜索