redis集群之主從複製集群的原理和部署

最近在復盤redis的知識,所以本文開始希望介紹下redis的集群架構、原理以及部署;本文主要介紹redis的主從複製集群,包括其架構模型,原理,高可用等;

一、主從集群的介紹

  redis的主從複製集群為了提高效率降低客戶端等待時長,主從間的數據同步採用的是弱一致性的策略,即客戶端請求發到主機後,不論是否同步到備機,都認為此次請求是成功的,這樣雖然效率上提高了,但是數據一致性卻得不到保障;所以redis提供了一個min-replicas-to-write參數用來配置,至少有幾台從機與主機保持連接時主機才能執行寫入操作,一定程度上維護了數據的一致性;
  其次,使用redis主從複製集群主要是為了解決單點故障問題,從機相當於主機的備份,且只提供讀不提供寫入功能,為的是在主機故障導致不能對外提供服務時從機能快速接替從而實現集群的高可用;而集群間主從的切換顯然不能通過人工來完成,所以redis提供了一個哨兵的概念,顧名思義,哨兵即負責監控放哨,當主機不可用時迅速從從機中選出一個主機來,而這又涉及到以下兩個方面;

  • 1、如何判斷redis集群的master不可用
    判斷master不可用使用的是過半機制,即當哨兵集群中某一個哨兵發現master不可用時,會向集群其他哨兵發送is-master-down-by-addr指令詢問master是否真的掛了,集群其他哨兵收到指令後會根據自身與master的連接情況判斷是否真的掛了,然後給第一個哨兵作出響應,是否贊成master掛了;當超過集群數量一半加1的機器認為master掛了那麼就投票通過,即認為redis集群的master真的掛了,需要進行選主操作;所以哨兵也應該是集群部署的,單個部署的話與主機是一對一的關係,不穩定性太大容易造成誤判
  • 2、哨兵發現master掛了過後又是如何給redis集群做主從個切換的呢(哨兵的選主)
    當第一個發現master掛了的哨兵收到其他哨兵的響應確認master掛了後,會繼續發送一個請求,希望自己成為哨兵的leader來進行redis集群的主從切換操作,此時該哨兵被稱為候選者;集群中的所有哨兵都只有一次投票機會,投給自己或者別人,需要注意的是只有候選者才能將票投給自己;哨兵之間的選主使用的是Raft算法

注意:
1、一般最先發現master掛了的哨兵會作為哨兵集群選主的候選者,會自動投給自己一票
2、如果同一時點有兩個哨兵同時發現master掛了,那麼就會有兩個候選者,他們都投給自己一票,需要注意的是集群中的每個哨兵只有一次投票機會,所以兩個候選者之外的哨兵肯定只會給兩個候選者中的一個投票

二、主從集群的安裝部署

我在安裝步驟里做了一些筆記,大概也囊括了主從複製的大部分特性,並且也貼上了關鍵命令執行的圖片,所以我就不拎出來單獨介紹了

1、環境準備

  • 1、先在linux下安裝redis,這裡我就不貼教程了,我安裝的是redis-5.0.5版本
  • 2、進入redis安裝目錄下的utils文件夾,執行 ./install_server.sh命令然後無腦回車,自動安裝redis服務,做集群的話則第一遍默認執行6379,第二遍第三遍可以把端口號換成6380和81,這樣我們主機里就有三個redis服務了
  • 3、安裝完後執行service redis_6379 stop、service redis_6380 stop和service redis_6381 stop分別停掉這三台主機,因為後續演示我們需要前台阻塞運行查看日誌
  • 4、在任意目錄下創建一個文件夾testRedis,然後把/etc下的redis的配置文件複製過來,因為我們集群測試會給一堆配置,所以另外複製一份,不動系統本身的配置,命令如下
    • mkdir testRedis
    • cd testRedis
    • cp /etc/redis/* ./
  • 5、編輯/testRedis下的三個配置文件,將
    • daemonize置為no,使redis服務前台運行,方便觀察日誌;
    • 注釋掉 logfile /var/log/redis_6379.log使其前台打印
    • appendonly置為no,關閉aof使其只使用rdb,具體原因後面會分析

    上面的配置完成後,表示接下來啟動的redis實例是會前台阻塞運行且不使用aof的持久化方式

  • 6、啟動三個redis實例
    • redis-server ~/testRedis/6379.conf
    • redis-server ~/testRedis/6380.conf
    • redis-server ~/testRedis/6381.conf
  • 7、啟動三個reids-cli連接三個實例
    • redis-cli -p 6379
    • redis-cli -p 6380
    • redis-cli -p 6381
  • 8、通過命令的方式使6380和6381作為slave追隨6379
    • 老版本命令 slaveof 127.0.0.1 6379
    • 新版本(5.0)命令 replicaof 127.0.0.1 6379

    注意:
    1、主從集群搭建完畢後,在6379set數據後80和81就能同步過去了,但是默認情況下80、81是不能寫入的,會報 READONLY You can’t write against a read only slave的錯誤;並且從機第一次追隨主機時是會flush掉本身所有數據的,會全量同步主機的數據過來;

  • 9、模擬從機下線
    • 6381下線重啟仍追隨6379,不開啟aof,命令如下:
      redis-server ~/testRedis/6381.conf –replicaof 127.0.0.1 6379
    • 6381下線重啟仍追隨6379,同時開啟aof,命令如下:
      redis-server ~/testRedis/6381.conf –replicaof 127.0.0.1 6379 –appendonly yes

1、由上面兩個圖可以看到,開啟aof時從機(6381)是會先flush掉自身數據重新從master(6379)身上全量同步數據的,所以從效率上來說增量同步肯定優於全量同步的
2、從機下線重啟後仍然追隨原主機(即下線前做過主從同步)的話,如果從機重啟時未開啟aof,那麼會做增量同步,否則則會進行全量同步;因為rdb中會記錄原主機信息而aof不會;

  • 10、模擬主機下線
    直接終止6379的進程,那麼此時6380和81會報Error condition on socket for SYNC: Connection refused錯誤,並且均只能提供讀服務不能提供寫入能力,所以此時可以人為的讓6380或6381使自己作為master,命令如下

    • replicaof no one
      然後再使另一個實例追隨新的matster,這樣redis集群又可以對外提供服務了,但是這種靠人為選主並切換終究不靠譜,所以就要用到哨兵模式,用來監控,當master掛了的時候能快速的響應,重新選主,使集群快速可用
  • 11、集群相關的配置
    • replica-serve-stale-data yes 從機同步主機數據期間是否將自己原本的舊數據對外暴露,默認對外暴露
    • replica-read-only yes 從機是否開啟只讀模式,默認從機只讀
    • repl-diskless-sync no 主機以何種方式將rdb文件同步給備機,yes表示主機生成rdb後直接通過網絡IO將數據發給備機;no的話表示主機先將rdb通過磁盤IO落本機磁盤再通過網絡傳送給備機;默認為先落磁盤再發送給從機
    • repl-backlog-size 1mb
      增量複製的大小;即當從機同步完後主機會維護一個增量數據的隊列,從機下次備份時可以拿着offset從隊列里直接取增量數據;默認是1m,但是需要根據業務的寫入量來確定該值大小;因為如果業務寫入過多,從機下線恢復這段時間寫入超過默認的1m的話,那麼只使用增量同步的話就會丟失數據了
    • min-replicas-to-write 3
      可以理解成master能否執行寫入操作的一個限制條件;當有指定個數的從機與主機保持連接時master才能執行寫操作;默認為當有3個從機與master保持連接master才能執行寫入操作,否則master不對外提供寫入能力;這樣雖然不能保證所有的從機都能同步到master的數據,但是可以保證至少有幾個從機存活master才能執行寫入操作,避免丟失過多數據;值為0表示關閉該限制
    • min-replicas-max-lag 10
      從機是否與主機保持連接的標準;默認為延遲小於10s的從機才被認為是健康的,是與主機保持連接的

三、哨兵集群搭建

  • 1、由於哨兵我們也搭建一個集群,所以創建三個哨兵的配置文件,在testRedis下執行以下命令
    • vi 26379.conf,按i輸入:
    • port 26379
    • sentinel monitor mymaster 127.0.0.1 6379 2

    一個redis哨兵集群可以監控多個redis集群,所以mymaster表示redis集群的名稱,後面跟redis集群master的ip和端口;最後一個數字2表示redis集群中幾個實例通過後投票有效,即我們常說的過半加1後的那個值,因為我的redis集群只有三台機器,所以這個值為3/2+1=2

    • cp 26379.conf 26380.conf 複製26379的配置,修改26380.conf里的port為26380
    • cp 26379.conf 26381.conf 複製26379的配置,修改26381.conf里的port為26381
  • 2、啟動redis集群中的各個實例,以6379為主6380和6381為slave追隨6379
  • 3、啟動哨兵集群
    • redis-server ./26379.conf –sentinel
    • redis-server ./26380.conf –sentinel
    • redis-server ./26381.conf –sentinel

    上圖,哨兵配置文件只配置了redis集群的主機ip和端口,但是哨兵啟動後卻獲取了整個redis集群所有實例的信息,是因為redis集群中從機追隨主機時主機已經知道從機的信息了,所以哨兵通過獲取主機信息既能獲取從機的信息
    另外,哨兵又是如何獲取其他哨兵的信息的呢?這是因為其使用了redis本身的發佈訂閱功能;即在redis集群的master上發佈各哨兵信息,哨兵們自行訂閱,可以通過在redis任意實例上執行PSUBSCRIBE * 來觀察哨兵之間的交互信息,如圖:

  • 4、當redis集群的master下線後哨兵集群是會自動修改自身的配置文件,將sentinel monitor mymaster後面換成最新的master的ip加端口,並且還會在配置文件後追加識別到的redis的其他從機和其他哨兵信息,如圖

    至此,redis的主從複製集群介紹完畢,如有紕漏還望指正!後續會繼續更新redis的分片集群……