1. 程式人生 > >最通俗易懂的 Redis 架構模式詳解

最通俗易懂的 Redis 架構模式詳解

![](https://mrhelloworld.com/resources/articles/redis/redis-300dpi.png " ") ## 前言      話說有一名義大利程式設計師,在 2004 年到 2006 年間主要做嵌入式工作,之後接觸了 Web,2007 年和朋友共同建立了一個網站,併為瞭解決這個網站的負載問題(為了避免 MySQL 的低效能),於是親自定做一個數據庫,並於 2009 年開發完成,這個就是 Redis。這個義大利程式設計師就是 Salvatore Sanfilippo 江湖人稱 Redis 之父,大家更習慣稱呼他 Antirez。    ![](https://mrhelloworld.com/resources/articles/redis/1aa358c7-1b07-36ba-b5ac-fa71694f95e0.png " ")      Redis 技術越來越火爆,其超高的效能,簡潔輕量的設計,易上手,分散式架構的支援,在快取等領域出色的表現造就了它現在的地位。   官方的 Benchmark 資料:測試完成了 50 個併發執行 10W 個請求。設定和獲取的值是一個 256 位元組字串。   結果:讀的速度是 110000次/s,寫的速度是 81000次/s。   為了滿足開發市場需求,Redis 支援**單機**、**主從**、**哨兵**、**叢集**多種架構模式,本文帶大家詳細講解這幾種架構模式的區別。    ## 單機模式 ![](https://mrhelloworld.com/resources/articles/redis/image-20200901193057781.png " ")   單機模式顧名思義就是安裝一個 Redis,啟動起來,業務呼叫即可。例如一些簡單的應用,並非必須保證高可用的情況下可以使用該模式。    ### 優點    - 部署簡單; - 成本低,無備用節點; - 高效能,單機不需要同步資料,資料天然一致性。    ### 缺點    - 可靠性保證不是很好,單節點有宕機的風險。 - 單機高效能受限於 CPU 的處理能力,Redis 是單執行緒的。      單機 Redis 能夠承載的 QPS(每秒查詢速率)大概在幾萬左右。取決於業務操作的複雜性,Lua 指令碼複雜性就極高。假如是簡單的 key value 查詢那效能就會很高。   假設上千萬、上億使用者同時訪問 Redis,QPS 達到 10 萬+。這些請求過來,單機 Redis 直接就掛了。系統的瓶頸就出現在 Redis 單機問題上,此時我們可以通過**主從複製**解決該問題,實現系統的高併發。    ## 主從複製 ![](https://mrhelloworld.com/resources/articles/redis/image-20200901192831745.png " ")   Redis 的複製(Replication)功能允許使用者根據一個 Redis 伺服器來建立任意多個該伺服器的複製品,其中被複制的伺服器為主伺服器(Master),而通過複製創建出來的複製品則為從伺服器(Slave)。 只要主從伺服器之間的網路連線正常,主伺服器就會將寫入自己的資料同步更新給從伺服器,從而保證主從伺服器的資料相同。   資料的複製是單向的,只能由主節點到從節點,簡單理解就是從節點只支援讀操作,不允許寫操作。主要是讀高併發的場景下用主從架構。主從模式需要考慮的問題是:當 Master 節點宕機,需要選舉產生一個新的 Master 節點,從而保證服務的高可用性。    ### 優點    - Master/Slave 角色方便水平擴充套件,QPS 增加,增加 Slave 即可; - 降低 Master 讀壓力,轉交給 Slave 節點; - 主節點宕機,從節點作為主節點的備份可以隨時頂上繼續提供服務;    ### 缺點    - 可靠性保證不是很好,主節點故障便無法提供寫入服務; - 沒有解決主節點寫的壓力; - 資料冗餘(為了高併發、高可用和高效能,一般是允許有冗餘存在的); - 一旦主節點宕機,從節點晉升成主節點,需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點,整個過程需要人工干預; - 主節點的寫能力受到單機的限制; - 主節點的儲存能力受到單機的限制。    ## 哨兵模式 ![](https://mrhelloworld.com/resources/articles/redis/image-20200902140230350.png " ")   主從模式中,當主節點宕機之後,從節點是可以作為主節點頂上來繼續提供服務,但是需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點,整個過程需要人工干預。   於是,在 Redis 2.8 版本開始,引入了哨兵(Sentinel)這個概念,在**主從複製的基礎**上,哨兵實現了**自動化故障恢復**。如上圖所示,哨兵模式由兩部分組成,哨兵節點和資料節點: - 哨兵節點:哨兵節點是特殊的 Redis 節點,不儲存資料; - 資料節點:主節點和從節點都是資料節點。      Redis Sentinel 是分散式系統中監控 Redis 主從伺服器,並提供主伺服器下線時自動故障轉移功能的模式。其中三個特性為: - 監控(Monitoring):Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常; - 提醒(Notification):當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式傳送通知; - 自動故障遷移(Automatic failover):當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。      接下來我們瞭解一些 Sentinel 中的關鍵名詞,然後系統講解下哨兵模式的工作原理。    ### 定時任務      Sentinel 內部有 3 個定時任務,分別是: - 每 1 秒每個 Sentinel 對其他 Sentinel 和 Redis 節點執行 `PING` 操作(監控),這是一個**心跳檢測**,是失敗判定的依據。 - 每 2 秒每個 Sentinel 通過 Master 節點的 channel 交換資訊(Publish/Subscribe); - 每 10 秒每個 Sentinel 會對 Master 和 Slave 執行 `INFO` 命令,這個任務主要達到兩個目的: - 發現 Slave 節點; - 確認主從關係。    ### 主觀下線      所謂主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 例項對伺服器做出的下線判斷,即單個 Sentinel 認為某個服務下線(有可能是接收不到訂閱,之間的網路不通等等原因)。   主觀下線就是說如果伺服器在給定的毫秒數之內, 沒有返回 Sentinel 傳送的 PING 命令的回覆, 或者返回一個錯誤, 那麼 Sentinel 會將這個伺服器標記為主觀下線(SDOWN)。    ### 客觀下線      客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 例項在對同一個伺服器做出 SDOWN 判斷,並且通過命令互相交流之後,得出的伺服器下線判斷,然後開啟 failover。   只有在足夠數量的 Sentinel 都將一個伺服器標記為主觀下線之後, 伺服器才會被標記為客觀下線(ODOWN)。只有當 Master 被認定為客觀下線時,才會發生故障遷移。    ### 仲裁      仲裁指的是配置檔案中的 `quorum` 選項。某個 Sentinel 先將 Master 節點標記為主觀下線,然後會將這個判定通過 `sentinel is-master-down-by-addr` 命令詢問其他 Sentinel 節點是否也同樣認為該 addr 的 Master 節點要做主觀下線。最後當達成這一共識的 Sentinel 個數達到前面說的 `quorum` 設定的值時,該 Master 節點會被認定為客觀下線並進行故障轉移。   `quorum` 的值一般設定為 Sentinel 個數的**二分之一加 1**,例如 3 個 Sentinel 就設定為 2。    ### 哨兵模式工作原理    1. 每個 Sentinel 以每秒一次的頻率向它所知的 Master,Slave 以及其他 Sentinel 節點發送一個 `PING` 命令; 2. 如果一個例項(instance)距離最後一次有效回覆 PING 命令的時間超過配置檔案 `own-after-milliseconds` 選項所指定的值,則這個例項會被 Sentinel 標記為**主觀下線**; 3. 如果一個 Master 被標記為主觀下線,那麼正在監視這個 Master 的所有 Sentinel 要以每秒一次的頻率確認 Master 是否真的進入主觀下線狀態; 4. 當有**足夠數量的 Sentinel**(大於等於配置檔案指定的值)在**指定的時間範圍內確認** Master 的確進入了主觀下線狀態,則 Master 會被標記為**客觀下線**; 5. 如果 Master 處於 **ODOWN 狀態**,則投票自動選出新的主節點。將剩餘的從節點指向新的主節點繼續進行資料複製; 6. 在正常情況下,每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有 Master,Slave 傳送 `INFO` 命令;當 Master 被 Sentinel 標記為客觀下線時,Sentinel 向已下線的 Master 的所有 Slave 傳送 INFO 命令的頻率會從 10 秒一次改為每秒一次; 7. 若沒有足夠數量的 Sentinel 同意 Master 已經下線,Master 的客觀下線狀態就會被移除。若 Master 重新向 Sentinel 的 PING 命令返回有效回覆,Master 的主觀下線狀態就會被移除。    ### 優點    - 哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都有; - 主從可以自動切換,系統更健壯,可用性更高; - Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。當被監控的某個 Redis 伺服器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程式傳送通知。    ### 缺點    - 主從切換需要時間,會丟失資料; - 還是沒有解決主節點寫的壓力; - 主節點的寫能力,儲存能力受到單機的限制; - 動態擴容困難複雜,對於叢集,容量達到上限時線上擴容會變得很複雜。    ## 叢集模式      假設上千萬、上億使用者同時訪問 Redis,QPS 達到 10 萬+。這些請求過來,單機 Redis 直接就掛了。系統的瓶頸就出現在 Redis 單機問題上,此時我們可以通過**主從複製**解決該問題,實現系統的高併發。   主從模式中,當主節點宕機之後,從節點是可以作為主節點頂上來繼續提供服務,但是需要修改應用方的主節點地址,還需要命令所有從節點去複製新的主節點,整個過程需要人工干預。於是,在 Redis 2.8 版本開始,引入了**哨兵(Sentinel)**這個概念,在**主從複製的基礎**上,哨兵實現了**自動化故障恢復**。   哨兵模式中,單個節點的寫能力,儲存能力受到單機的限制,動態擴容困難複雜。於是,Redis 3.0 版本正式推出 **Redis Cluster 叢集**模式,有效地解決了 Redis 分散式方面的需求。Redis Cluster 叢集模式具有**高可用**、**可擴充套件性**、**分散式**、**容錯**等特性。    ![](https://mrhelloworld.com/resources/articles/redis/20041523528353133303113714.png " ")      Redis Cluster 採用無中心結構,**每個節點都可以儲存資料**和整個叢集狀態,每個節點都和其他所有節點連線。Cluster 一般由多個節點組成,節點數量至少為 6 個才能保證組成完整高可用的叢集,其中三個為主節點,三個為從節點。三個主節點會分配槽,處理客戶端的命令請求,而從節點可用在主節點故障後,頂替主節點。   如上圖所示,該叢集中包含 6 個 Redis 節點,3 主 3 從,分別為 M1,M2,M3,S1,S2,S3。除了主從 Redis 節點之間進行資料複製外,所有 Redis 節點之間採用 Gossip 協議進行通訊,交換維護節點元資料資訊。   總結下來就是:讀請求分配給 Slave 節點,寫請求分配給 Master,資料同步從 Master 到 Slave 節點。    ### 分片      單機、主從、哨兵的模式資料都是儲存在一個節點上,其他節點進行資料的複製。而單個節點儲存是存在上限的,叢集模式就是把資料進行**分片**儲存,當一個分片資料達到上限的時候,還可以分成多個分片。   Redis Cluster 採用**虛擬雜湊槽分割槽**,所有的鍵根據雜湊函式對映到 0 ~ 16383 整數槽內,計算公式:`HASH_SLOT = CRC16(key) & 16384`。每一個節點負責維護一部分槽以及槽所對映的鍵值資料。 ![](https://mrhelloworld.com/resources/articles/redis/20041523528594766267635978.png " ")   Redis Cluster 提供了靈活的節點擴容和縮容方案。在不影響叢集對外服務的情況下,可以為叢集新增節點進行擴容也可以下線部分節點進行縮容。可以說,槽是 Redis Cluster 管理資料的基本單位,叢集伸縮就是槽和資料在節點之間的移動。   簡單的理解就是:擴容或縮容以後,槽需要重新分配,資料也需要重新遷移,但是服務不需要下線。      假如,這裡有 3 個節點的叢集環境如下: - 節點 A 雜湊槽範圍為 0 ~ 5500; - 節點 B 雜湊槽範圍為 5501 ~ 11000; - 節點 C 雜湊槽範圍為 11001 ~ 16383。   此時,我們如果要儲存資料,按照 Redis Cluster 雜湊槽的演算法,假設結果是: CRC16(key) & 16384 = 6782。 那麼就會把這個key 的儲存分配到 B 節點。此時連線 A、B、C 任何一個節點獲取 key,都會這樣計算,最終通過 B 節點獲取資料。   假如這時我們新增一個節點 D,Redis Cluster 會從各個節點中拿取一部分 Slot 到 D 上,比如會變成這樣: - 節點 A 雜湊槽範圍為 1266 ~ 5500; - 節點 B 雜湊槽範圍為 6827 ~ 11000; - 節點 C 雜湊槽範圍為 12288 ~ 16383; - 節點 D 雜湊槽範圍為 0 ~ 1265,5501 ~ 6826,11001 ~ 12287   這種特性允許在叢集中輕鬆地新增和刪除節點。同樣的如果我想刪除節點 D,只需要將節點 D 的雜湊槽移動到其他節點,當節點是空時,便可完全將它從叢集中移除。    ### 主從模式      Redis Cluster 為了保證資料的高可用性,加入了主從模式,**一個主節點對應一個或多個從節點**,主節點提供資料存取,從節點複製主節點資料備份,當這個主節點掛掉後,就會通過這個主節點的從節點選取一個來充當主節點,從而保證叢集的高可用。   回到剛才的例子中,叢集有 A、B、C 三個主節點,如果這 3 個節點都沒有對應的從節點,如果 B 掛掉了,則叢集將無法繼續,因為我們不再有辦法為 5501 ~ 11000 範圍內的雜湊槽提供服務。   所以我們在建立叢集的時候,一定要為每個主節點都新增對應的從節點。比如,叢集包含主節點 A、B、C,以及從節點 A1、B1、C1,那麼即使 B 掛掉系統也可以繼續正確工作。   因為 B1 節點屬於 B 節點的子節點,所以 Redis 叢集將會選擇 B1 節點作為新的主節點,叢集將會繼續正確地提供服務。當 B 重新開啟後,它就會變成 B1 的從節點。但是請注意,如果節點 B 和 B1 同時掛掉,Redis Cluster 就無法繼續正確地提供服務了。    ### 優點    - 無中心架構; - 可擴充套件性,資料按照 Slot 儲存分佈在多個節點,節點間資料共享,節點可動態新增或刪除,可動態調整資料分佈; - 高可用性,部分節點不可用時,叢集仍可用。通過增加 Slave 做備份資料副本。 - 實現故障自動 failover,節點之間通過 gossip 協議交換狀態資訊,用投票機制完成 Slave 到 Master 的角色提升。    ### 缺點    - 資料通過非同步複製,無法保證**資料強一致性**; - 叢集環境搭建複雜,不過基於 Docker 的搭建方案會相對簡單。    ## 總結      隨著網際網路的飛速發展,我們享受著技術帶來的便利,同時也給從業者帶來了如何保證專案高併發、低延時的技術挑戰。Redis 以其超高的效能,簡潔輕量的設計,易上手,分散式架構的支援,在快取等領域出色的表現等,得到了業界廣泛的關注和應用,在當今高效能架構中,也發揮著越來越重要的作用。甚至可以說,Redis 已經成為 IT 網際網路大型系統的標配,熟練掌握 Redis 成為開發、運維人員的必備技能。   如果不深挖底層,僅僅只是從使用的角度出發,Redis 的學習成本將會非常低。如果作為一個很好的中介軟體去研究的話,還是有很多值得學習和借鑑的地方。以上幾種模式,每種都有各自的優缺點,在實際場景中要根據業務特點去選擇合適的模式使用。    ## 參考資料    - https://redis.io/topics/replication - https://redis.io/topics/sentinel - https://redis.io/topics/cluster-tutorial - https://redis.io/topics/cluster-spec ![](https://user-gold-cdn.xitu.io/2020/5/1/171cf87f564bc82e?w=433&h=133&f=gif&s=333013) 本文采用 `知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議`。 大家可以通過 `分類` 檢視更多關於 `Redis` 的文章。