博客 / 詳情

返回

從0到1構建一個穩定redis架構

從0到1搭建一個穩定的redis集羣

1、單機版redis

  單機版的redis就是業務系統把他用作緩存使用,從mysql中查詢數據然後寫入到redis中,後面再查詢的時候就會優先查詢緩存。因為redis運行在內存中,所以速度很快。若業務體量不大,這樣似乎可以滿足需求了。但是隨着業務體量的擴大,redis中存儲的數據越來越多,此時業務對redis的依賴也越來越多。假設有一種情況,redis因為某些原因宕機了,請求都會打到mysql上,導致mysql壓力突增。

  這時候能想到的做法可能是重啓redis,但是因為redis運行在內存,重啓後數據就丟失了,雖然可以正常工作,但沒有任何數據,請求還是會打到mysql上。

  那麼你就會想,有沒有什麼辦法能讓redis重啓後數據仍然存在呢?那就是把數據寫到磁盤上。

2、數據持久化

  那數據持久化怎麼做呢?一個簡單的思路是當每次redis進行寫操作時,都把數據再存一份到磁盤上。但是這樣做又會導致redis的壓力增大,因為要寫磁盤!

  那如何解決?優化思路是,redis的寫內存由主線程來做,寫內存完後就返回給客户端,redis用另外一個線程去寫磁盤,這樣就可以併發操作。

  那麼換一個角度,我們用redis通常是用來做緩存,是為了把數據庫中的數據寫到緩存中,減輕查詢的壓力。那麼就算redis中不存在這些數據,找數據庫也能拿到,只是速度慢一些。所以就有了用【數據快照】的持久化方法。這種方式的優點是除了在【持久化】的時刻要把數據一次性寫入磁盤,其他時間都不需要操作磁盤。

  以上兩種方法就對應redis的兩種持久化方案RDB和AOF。除此之外,還有以下這些特點:

  • RDB:只持久化某一時刻的快照數據到磁盤上(創建一個子進程來做)。用二進制+數據壓縮的方式寫磁盤,佔用空間小,數據恢復也快。
  • AOF:每一次寫都記錄到磁盤(主線程寫內存,根據策略可以配置由主線程還是子線程進行數據持久化)。AOF記錄的是每一次寫命令,數據最全,但文件體積大,數據恢復速度慢。
  • 如果業務對數據丟失不敏感,可以用RDB;若業務對數據完整性要求較高,採用AOF。但如果只用AOF也會出現問題:AOF記錄每一次寫操作,隨着時間增長,AOF體積會越來越大。而且在數據恢復的時候也很慢。

  那麼有什麼辦法,既可以縮小文件體積,又可以提升恢復速度呢?我們這裏想一下,因為AOF記錄是每一次寫操作,對於同一個key可能會進行多次操作,那麼是否可以只保留最終的結果呢?這就是【AOF rewrite】。我們可以定時rewrite,避免文件持續膨脹,這樣在恢復的時候就可以縮短時間了。

  那有沒有什麼辦法繼續縮小AOF文件呢?那就是redis的【混合持久化】。具體來説,當AOF rewrite時,redis先以RDB格式在AOF文件中寫入一個數據塊找,再把這期間內產生的每一個寫命令加入到AOF文件中。(redis4.0版本以上才支持混合持久化)。

  雖然現在已經把持久化的文件優化到最小了,但在恢復數據時依舊需要時間,這期間業務還是會受到影響,怎麼辦?一個實例宕機,只能用恢復數據來解決,是否可以部署多個redis實例,讓這些實例數據保持同步,這樣在一個redis宕機時可以在剩下的實例中選一個繼續提供服務。【主從複製】

3、主從複製

  主從複製的形式就是會有一個主節點,以及一個/多個從節點。這樣做的優勢是:

  • 縮短不可用時間:master宕機可以手動把從節點提升為主節點。
  • 提升讀性能:讓從節點分擔一部分讀請求,提升整體性能。

  但這裏存在一個問題,就是在主節點宕機時,需要手動把從節點提升為主節點,這個過程要花費時間。雖然比恢復數據要快,但還是要人工介入。那怎麼去解決這個問題呢?——就有了接下來的【故障自動切換機制】。

4、 哨兵:故障自動切換

  我們在這種模式會引入觀察者(哨兵),這個觀察者不存儲數據,只是會去實時監測節點的健康狀態。

  但這裏還存在一個問題,就是如果哨兵與主節點之間的網絡除了問題,這個哨兵可能會誤判!這裏我們就可以部署多個哨兵,讓它們部署在不同的機器上,一起監測主節點的狀態,流程如下:

  • 多個哨兵隔一段時間就詢問主節點是否正常。
  • 主節點正常恢復,表示狀態正常,回覆超時表示異常。
  • 一旦有一個哨兵判定master異常【主觀下線】,就會問其他哨兵,若多個哨兵都認為主節點異常(設置一個閾值),就會判定主節點確實發生了故障【客觀下線】。

  那麼確定主節點故障後,由哪個哨兵進行主從切換呢?這裏我們採用基於raft算法的領導選舉規則:1)每個哨兵問其他哨兵,請求對方為自己投票;2)如果對方已經給別人投了票,就不能給他投票;若還沒投票,就投給他;3)當第一個拿到超過半數投票的哨兵,當選為領導者。(分佈式系統領域中的共識算法)

  那麼隨着時間推移,業務體量越來越大,此時這個架構模型還能承擔這麼大的流量嗎?以前的做法是,主節點承擔寫操作,從節點承擔讀操作,但是當業務流量暴增的時候,主節點還能承受這麼大的寫流量嗎?——這裏就考慮到了【分片集羣】。

5、 分片集羣:橫向擴展

  多實例如何組織?

  1)每隔節點各自存儲一部分數據,所有節點的數據之和才是全量數據。

  2)指定一個路由規則,對不同的key把它路由到一個實例上進行讀寫。

   這種思路可以根據所在位置不同分為兩類:

  1)客户端分片:key的路由規則放在客户端來做,但缺點是客户端需要維護這個路由規則。那如何不在業務代碼耦合這些代碼呢?就是把路由規則封裝成一個模塊,當要使用時集成這個模塊就可以了。這就是redis Cluster採用的方案。(其中內置了哨兵邏輯,不用再部署哨兵)

  2)服務端分片:路由規則不放在客户端來做,而是在客户端和服務端之間引入一個【中間代理層】。這個代理會把你的請求根據路由規則,轉發到對應的redis節點上,當集羣實例不足以支撐更大的流量請求時可以橫向擴容,添加新的redis實例提升性能。這些操作對於客户端來説都是無感知的。

 

 

參考:公眾號水滴與銀彈

 

user avatar venmos 頭像 pudongping 頭像 yaoyaolx_wiki 頭像 boywus 頭像 tingtr 頭像 fedl 頭像 dadegongjian 頭像 xushuhui 頭像 chenmingyong 頭像 shenlan_5f8fa163e8542 頭像 zhujiu 頭像 kumenderiguangdeng 頭像
21 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.