Redis高可用-主從,哨兵,集羣

主從複製

Master-Slave主從概念

同時運行多個redis服務端,其中一個做爲主(master),其餘的一個或多個做爲從(slave),主從之間經過網絡進行通信,slave經過複製master的數據來保持與master的數據同步,實現數據冗餘;node

在Redis中,配置主從複製很是簡單,Redis容許slave實例對master進行完整拷貝,在鏈接斷開時,slave會自動從新鏈接至主實例,並儘量與master保持同步;redis

三個主要機制:

  • 當鏈接可用時,master將發送命令流到slave來使salve保持更新,如下操做將引起該操做,對msater數據的寫入操做(包括刪除更新),key過時;
  • master和slave節點都會進行超時檢測,當鏈接不穩定時,slave將盡快從新鏈接並進行部分從新同步,即不須要徹底從新同步;
  • 若沒法進行部分從新同步,則slave將發起徹底從新同步,master會將最新的數據快照發送給slave,後續的操做仍然是發送命令流;

其餘特性:

主從之間,採用異步複製,複製過程當中依然能夠正常響應客戶端操做,支持一主多從,且從節點還能夠相似的級聯其餘從節點,如圖所示:算法

image-20200526184118562

主從複製的做用:

  • 使用主從複製,可以避免Redis的單點故障,實現數據防災備份;
  • 可配置主節點執行寫入,多個從節點分擔查詢,實現讀寫分離得到更好的性能

注意:使用主歷來作讀寫分離時,意味主節點自身沒有任何持久化數據;若是配置了哨兵,一旦節點重啓,則將使用空數據進行同步,致使從節點覆蓋全部持久化數據,這是很是危險的,牆裂建議在主節點和從節點上開啓持久化,若是必定要關閉,則必須配置主節點禁止哨兵自動重啓故障節點;具體故障模式:鏈接shell

配置:

#配置文件中按如下方式添加主節點的ip 和端口便可
replicaof 192.168.1.1 6379
#若主節點配置了受權密碼則須要指定密碼
masterauth 密碼
#主節點經過如下方式設置受權密碼
requirepass 密碼
#客戶端鏈接後須要先驗證密碼
auth 密碼

#可經過如下指令查看當前鏈接的服務的主從信息
info replication

副本只讀:

默認狀況下副本是隻讀的,若須要能夠經過配置replica-read-onlyno來使副本變爲可寫的,可是要強調的是副本寫入的數據,僅寫入到當前副本本地,不會同步至任何節點,包括當前副本的副本;當副本重啓後這寫數據將消失,即臨時數據;安全

哨兵

哨兵(Sentinel) 是爲redis提供了高可用性(high available/HA),使用Sentinel部署Redis時,可實如今無需人工干預的狀況下,自動完成固定類型的故障修復;是Redis儘量處於正常工做狀態;服務器

哨兵的主要功能:網絡

  • 集羣監控:監控redis各個節點是否正常工做;
  • 消息通知:當某個節點出現故障時,可經過API\通知系統管理員或是其餘程序;
  • 故障轉移(failover):當master沒法沒法正常工做時,哨兵能夠啓動故障轉移過程,該過程會將某一個slave節點提高爲master節點,並主動通知使用redis服務器的應用程序要使用新的地址;
  • ​ 配置中心:當客戶端鏈接至哨兵時,可經過哨兵獲取可用的Redis服務信息;

哨兵的分佈式性質:異步

Sentinel自己是一個分佈式系統,即會有多個Sentinel進程經過網絡協同合做,具備如下優勢:分佈式

  • 當多個哨兵就某一master不可用這一事實達成共識,纔會進行故障轉移,下降了因網絡波動形成誤報的可能性;性能

  • 即便一些哨兵進程沒法工做時,其餘可用的哨兵仍然可以正常工做,提供了整個系統應對故障的能力;

    反過來,若是隻有單獨的一個哨兵進程其實是沒有辦法提供高可用的;

啓動哨兵

哨兵的執行文件本質就是redis的服務端,只不過運行的模式不一樣了,另外運行哨兵必須提供配置文件,不然將拒絕啓動;

首先須要準備配置文件,在下載的源碼中找到sentinel.conf 爲了後續方便修改能夠將其複製到bin目錄下

指定master的地址和端口

sentinel monitor mymaster 127.0.0.1 6379 2

啓動哨兵的命令有兩種寫法:

#方式1
redis-sentinel sentinel.conf
#方式1
redis-server sentinel.conf --sentinel

若啓動哨兵成功能夠在控制檯中看到其輸出的master節點信息;

image-20200527114018119

默認狀況下哨兵監聽在26379端口上,若開啓了防火牆則須要開放該端口,不然哨兵沒法正常工做;

完成故障切換的過程

故障切換的定義:

​ 當master不可用時將一個可用的slave提高稱爲master,使結點保持正常訪問;

基於網絡存在不穩定性這個特性,一些時候某個哨兵進程可能沒法與master正常通信,可是這並不意味這master真的不可用了,哨兵沒法就此認定master不可用這一事實,哨兵須要可以檢測master是否客觀的不可用了,並在master不可用成爲客觀事實後開始執行故障切換;

  1. 每一個Sentinel(哨兵)進程以每秒鐘一次的頻率向整個集羣中的Master主服務器,Slave從服務器 以及其餘Sentinel(哨兵)進程發送一個 PING 命令
  2. 若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after- milliseconds 選項所指定的值,則這個實例會被 Sentinel(哨兵)進程標記爲主觀下線(sdown)
  3. 若是一個Master主服務器被標記爲主觀下線(SDOWN),則正在監視這個Master主服務器的全部Sentinel(哨兵)進程要以每秒一次的頻率確認Master主服務器的確進入了主觀下線狀態。
  4. 當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間範圍內確認Master主服務器進入了主觀下線狀態(SDOWN), 則Master主服務器會被標記爲客觀下線(ODOWN)。
  5. 在通常狀況下, 每一個Sentinel(哨兵)進程會以每 10 秒一次的頻率向集羣中的全部Master主服務器、Slave從服務器發送 INFO 命令。
  6. 當Master主服務器被 Sentinel(哨兵)進程標記爲客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master主服務器的全部 Slave從服務器發送 INFO 命令的頻率會從 10 秒一次改成每秒一次。
  7. 若沒有足夠數量的 Sentinel(哨兵)進程贊成 Master主服務器下線, Master主服務器的客觀下線狀態就會被移除。若 Master主服務器從新向 Sentinel(哨兵)進程發送 PING 命令返回有效回 復,Master主服務器的主觀下線狀態就會被移除。

故障切換涉及到的事件和參數:

  • sdown:主觀下線,當某個哨兵與master之間在指定時間內沒法正常通信後該哨兵將產生sdown事件

  • quorum(仲裁數):是一個整數,表示master從主觀下線變爲客觀下線所須要的哨兵數量(但有quorum個哨兵與master通信失敗則master進入主觀下線)

  • odown:當sdown的事件的數量達到指定值(quorum)時,將產odown事件,表示master客觀下線了;

  • majority(大多數):是一個整數,該值經過計算自動得出,計算公式爲floor(哨兵總數量/2)+1 floor爲下取整

當odown產生時,會選出一個哨兵準備進行故障切換,在切換前該哨兵還須要得到大多數(majority)哨兵的受權,受權成功則開始進行故障切換;

故障切換完成後,若先前宕機的節點(原來的master)恢復正常,則該節點會降爲slave;

部署Sentinel的基本知識

  • 哨兵應與分佈式的形式存在,若哨兵僅部署一個則實際上沒有辦法提升可用性,當僅有的哨兵進程遇到問題退出後,則沒法完成故障恢復;

  • 一個健壯的部署至少須要三個Sentinel實例

  • 三個哨兵應該部署在相互的獨立的計算機或虛擬機中;

  • Sentinel沒法保證在執行故障轉移期間的寫入的數據是否可以保留下來;

部署案例:

下例圖中名稱的釋義:
S:sentinel

M:master

R:replace(slave)

1.不要採用下例部署

image-20200528125919633

上述部署中若M1(包括S1,由於在同一個機器上)宕機,剩下的S2雖然能夠認定M1主觀下線,可是卻沒法獲得大多數哨兵的受權並開始故障切換,由於此時majority爲2;

2.簡單且實用的部署

image-20200528130347251

上述部署由三個節點組成,每一個節點都運行着Redis進程和Sentinel進程,結構簡單,安全性也有了提升;

當M1發生故障時,S2和S3能夠就該故障達成一致,而且可以受權進行故障切換,從而使得客戶端能夠正常使用;但也存在丟失已寫入數據的狀況,由於redis內部使用異步複製,Master和Slave之間的數據在某個時間點可能不一致;

注意:

image-20200528130949015

因爲網絡存在分區性質,若客戶端C1和M1處於同一分區,可是該分區與S1,S2所在的分區沒法通信時,C1能夠繼續向M1寫入數據,這寫數據將丟失,由於當網絡恢復時,M1可會被降爲slave,而丟棄本身本來的數據;

使用下例配置可緩解該問題:

min-replicas-to-write 1
min-replicas-max-lag 5

上述配置表示,只要master沒法寫入數據到任何一個slave超過5秒,則master中止接受寫入;

3.在客戶端部署哨兵

若某些緣由致使沒有足夠的服務器節點用於部署哨兵,則能夠將哨兵部署至客戶端,以下所示

image-20200528132017887

若M1出現故障,則S1,S2,S3可順利的進行故障切換;但要注意該部署可能出現案例2中的問題

固然你也能夠在客戶端和服務端同時部署哨兵;

配置示例:

#指出master地址和端口  以及仲裁數
sentinel monitor mymaster 127.0.0.1 6379 2
# 與master通信超時時間,達到超時時間則sdown+1
sentinel down-after-milliseconds mymaster 60000
# 同一個master,開始新的故障轉移的時間(將是上一次的兩倍)
# 若slave鏈接到錯誤的master超過這個時間後slave將被從新鏈接到正確的master
# 取消正在進行中的故障轉移等待時間
# 按照parallel-syncs指定的配置進行復制的時間,超時候將再也不受parallel-syncs的限制
sentinel failover-timeout mymaster 180000
# 發生故障轉移後,同時進行同步的副本數量
sentinel parallel-syncs mymaster 1

集羣

Redis 集羣是一個提供在多個Redis間節點間共享數據的程序集。

Redis集羣並不支持處理多個keys的命令(如mset),由於這須要在不一樣的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的狀況下可能會致使不可預料的錯誤.

Redis 集羣經過分區來提供必定程度的可用性,在實際環境中當某個節點宕機或者不可達的狀況下繼續處理命令. Redis 集羣的優點:

  • 自動分割數據到不一樣的節點上。
  • 整個集羣的部分節點失敗或者不可達的狀況下可以繼續處理命令。

示意圖:

image-20200602161912338

集羣的數據分片

Redis 集羣沒有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集羣有16384個哈希槽,每一個key經過CRC16算法校驗後對16384取模來決定放置哪一個槽.集羣的每一個節點負責一部分hash槽,舉個例子,好比當前集羣有3個節點,那麼:

  • 節點 A 包含 0 到 5500號哈希槽.
  • 節點 B 包含5501 到 11000 號哈希槽.
  • 節點 C 包含11001 到 16384號哈希槽.

這種結構很容易添加或者刪除節點. 好比若是我想新添加個節點D, 我須要從節點 A, B, C中得部分槽到D上. 若是我想移除節點A,須要將A中的槽移到B和C節點上,而後將沒有任何槽的A節點從集羣中移除便可. 因爲從一個節點將哈希槽移動到另外一個節點並不會中止服務,因此不管添加刪除或者改變某個節點的哈希槽的數量都不會形成集羣不可用的狀態.

客戶端能夠訪問任意節點進行讀寫操做,若哈希槽不在當前訪問的節點redis會自動的將指令移動到相關節點上;

主從複製模型

爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,集羣使用了主從複製模型,每一個節點都會有至少一個slave;

集羣在沒有slave的狀況下,若是某個節點故障了,那麼整個集羣就會覺得缺乏一部分槽而不可用.

然而若是在建立集羣時爲每一個節點都添加了從節點,在某個節點故障後,其從節點將被選舉爲新的主節點,整個集羣就不會因找不到槽而不可用,固然若某個節點與其全部子節點都故障了那麼整個節點將不可用;

一致性保證

Redis 並不能保證數據的強一致性. 這意味這在實際中集羣在特定的條件下可能會丟失寫操做,主要有兩方面緣由:

  • 主節點到從節點之間的指令複製是異步完成的,主從之間在某個時間點可能不一致
  • 出現網絡分區,致使主節點可正常寫入,可是從節點已經被其餘分區節點選舉爲新的master,寫入的數據將丟失

容錯性

image-20200602165948571

當某master節點故障時,其餘master節點將發起投票,若一半以上的master認爲其不可用,則從該節點的從節點中(若存在)選舉新的master;

若該master沒有從節點,則集羣將不可用

另外當集羣一半以上的節點都不可用時則不管這些節點是否有從節點,集羣當即不可用;

建立集羣:

Redis在5.0版本時放棄了Ruby集羣的方式,改成C語言編寫的 redis-cli方式,使得集羣的構建方式複雜度大大下降。

集羣至少須要三個節點,每一個節點一個從節點總共爲6個

  1. 配置:

    若要以集羣方式運行,則須要按如下方式修改配置文件,以啓用集羣:

    cluster-enabled yes

    在實際開發中仍然建議使用單獨的虛擬機來部署全部的redis節點,下例爲了簡化操做,在同一臺虛擬機上搭建集羣來進行測試:

  2. 添加上述配置後將bin目錄複製6分名稱爲7001-7006,端口從7001-7006

    image-20200602174538250

  3. 分別啓動6個redis示例

    image-20200602174555152

  4. 使用redis-cli建立集羣

    redis-cli --cluster create 10.211.55.9:7001 10.211.55.9:7002 10.211.55.9:7003 10.211.55.9:7004 10.211.55.9:7005 10.211.55.9:7006 --cluster-replicas 1

    過程當中集羣將重寫配置文件,需輸入yes確認

    建立完成後提示以下信息:

    ![image-20200602174849244](/Users/jerry/Library/Application Support/typora-user-images/image-20200602174849244.png)

    能夠看到,集羣自動爲每一個master平均分配了哈希槽,而且設置了一個slave

  5. 鏈接集羣

    ./redis-cli -h 10.211.55.9 -p 7001 -c
    # 參數 -c 即表示鏈接到集羣
  6. 查看集羣狀態

    cluster info
  7. 查看節點信息,包括ip,port,id,槽,主/從;

    cluster nodes

添加節點

Redis集羣支持動態擴展,期間redis可正常響應客戶端訪問

  1. 首先製做新的redis實例端口爲7007並啓動

  2. 添加到集羣中

    ./redis-cli --cluster add-node 10.211.55.9:7007 10.211.55.9:7001

    添加成功:

    image-20200602180930266

  3. 新的節點默認做爲master,可是該master沒有分配槽位,使用前必須分配哈希槽

    下例表示從id爲cc2e48268ccdd52d1c7840c8f9d2d7f15cc74c1b的節點移動1000個槽到cda3828e42e23dcbdb141db2fed221bc07c59f65節點

    ./redis-cli --cluster reshard 10.211.55.9:7001 --cluster-from cc2e48268ccdd52d1c7840c8f9d2d7f15cc74c1b --cluster-to cda3828e42e23dcbdb141db2fed221bc07c59f65 --cluster-slots 1000
    #--cluster-from  來源節點 多個以前用逗號隔開, all 表示從全部節點中平均分配
    #--cluster-to    目標節點
    #--cluster-slots 1000  移動哈希槽數量
  4. 爲新的master添加從節點

  • 再次啓動一個新的實例

    • 添加至集羣並指定爲某master的slave

      ./redis-cli --cluster add-node 10.211.55.9:7008 10.211.55.9:7001 --cluster-slave --cluster-master-id cda3828e42e23dcbdb141db2fed221bc07c59f65
      #--cluster-slave 指定新節點做爲slave
      #--cluster-master-id 指定新節點的master

刪除節點

  1. 刪除從節點7008

    ./redis-cli --cluster del-node 10.211.55.9:7008 887d2f115f6a94bda86863576d73a131f12229d5
    #指定集羣host:port  和要刪除的節點id
  2. 將主節點的哈希槽分配給其餘的主節點

    /redis-cli --cluster reshard 10.211.55.9:7001 --cluster-from cda3828e42e23dcbdb141db2fed221bc07c59f65 --cluster-to cc2e48268ccdd52d1c7840c8f9d2d7f15cc74c1b
  3. 刪除主節點

    ./redis-cli --cluster del-node 10.211.55.9:7007 887d2f115f6a94bda86863576d73a131f12229d5
    #指定集羣host:port  和要刪除的節點id
  4. 哈希槽均衡,該操做檢查各節點的槽均衡狀況,若差別較大則自動從新分配

    ./redis-cli --cluster rebalance 10.211.55.9:7001
相關文章
相關標籤/搜索