關於Redis的主從複製與哨兵機制,看完這篇面試官都覺得NB Redis的主從複製 建立主從連接 同步數據 全量複製 部分複製 Redis的哨兵 監控節點 發現故障 故障轉移

Redis的主從複製

單機的redis情況下,不能滿足所有的需求

  1. 機器故障,當機器發生故障時,可能導致數據丟失,redis將不能提供服務
  2. 單機性能瓶頸,一臺機器的硬件提升是有上限的,不能一直提升,並且一臺機器到後面能夠提升的空間越來越小,而代價卻越來越高

所以,除了縱向提升服務器性能外,可以橫向提升服務器規模,部署多個redis服務器,同時也避免單點redis服務器的機器故障,只需要保證這多臺redis服務器的數據都是同步的。即使有某臺服務器發生故障,也不影響其他服務器提供服務

主節點和從節點都可以進行服務,從節點複製主節點的數據,主節點宕機後,從節點可以提供服務

  • 一個master可以用多個slave
  • 一個slave只能有一個master
  • 數據只能由master流向slave

這種一主多從架構,可以實現高可用,讀寫分離

建立主從連接

有幾種建立連接的方式,分別是主動命令設置配置文件設置

  • slaveof ip port 命令(異步)
  • slave of no one 從節點斷開連接,但是之前同步的數據不會清零,只是不再同步主節點的數據

從節點向指定ip和端口的主節點發送請求命令,連接建立後就清空從節點數據,開始複製主節點數據。使用命令建立的好處是,不需要重啓服務器,一條命令就能馬上建立。

配置文件設置

在配置文件中有關於主從複製的相關配置,配置文件設置的優點是適用於集中管理,不過需要重啓redis,通常使用配置文件來實現。

  • slaveof host port 設置主節點的ip和端口
  • slave-read-only yes 從節點只讀:yes

slave節點設置爲只讀,可以防止被修改,避免從庫和主庫的數據不一致。同時可以實現讀寫分離。

同步數據

主從建立後,從節點就開始同步主節點數據了,同步數據的方式分爲全量複製部分複製

主從連接第一次建立或者slave節點重啓,使用的是全量複製。全量複製會將master節點的所有數據發送給slave節點,是一個重量級的操作。

數據傳輸過程中,有這幾個關鍵的屬性:

  • runid:一串40個隨機十六進制字符組成的字符串,用於唯一標識當前運行的服務器,是在服務器啓動時自動隨機生成。主從連接後,master會將自己的runid發給slave存儲,用於識別傳輸身份。
  • 複製緩衝區:也叫複製積壓緩衝區,是一個FIFO隊列,默認大小爲1mb,用於存儲服務器執行的更新命令。當命令總量超出緩衝容量,會彈出最早的命令。服務器如果開啓AOF持久化方式或被設置爲主節點,就會創建複製緩衝區。
  • offset:是複製緩衝區中的命令偏移量,在緩衝區中,命令以AOF格式的字節存儲,通過offset記錄了命令的位置。master會記錄上次發給所有slave的offset,通過比對slave發過來的offset,找到緩衝區隊列中的位置,發送後續的所有命令。

如果master執行shutdown save命令的話,會進行RDB持久化,保存master當前的runid和offset,重啓恢復數據後,能夠讓slave認爲還是之前的master

全量複製

全量複製的步驟如下圖

上面提到全量複製是一個重量級的操作,主要有這些方面的開銷

  1. master進行bgsave
  2. 傳輸RDB文件
  3. slave清空數據加載RDB
  4. 可能的AOF

部分複製

redis2.8之後提供了部分複製,在某些情況下,使用更輕量的部分複製,減少開銷。不過當部分複製的條件不滿足時,仍然會使用全量複製。

比如主從連接因爲網絡原因丟包,重新建立連接後,判斷是否能進行部分複製。

  1. slave會發送之前存儲的master的runid和offset,判斷是否是同一臺服務器,以及記錄的數據位置是否仍在緩衝區隊列中
  2. 如果其中一個不滿足,就進行全量複製
  3. 如果都相同,就忽略
  4. 如果offset不同,且在緩衝區內有記錄,就進行部分複製

心跳機制

在同步命令時的master和slave採取了心跳機制來交換數據。

  • slave心跳,每隔一秒都會發送REPLCONF ACK {offset},嘗試獲取最新記錄的命令,同時也可以判斷master是否在線
  • master心跳,以一個固定的時間間隔repl-ping-slave-period(默認10秒)去ping從節點,輪詢slave是否還在線。master會根據slave發送的命令,判斷工作的slave數量和延遲。當數量或延遲不滿足要求時,master會強制關閉寫功能,暫停數據同步,用來保障數據的穩定性

故障轉移

如果服務器發生了故障,我們需要轉移故障,讓剩下的節點仍然能保證正常工作。

比如slave服務器發生故障,可以將連接故障slave的客戶端,轉去使用其他的slave,但是需要注意的是:另一個服務器如果突然增加很多客戶端,壓力也會增大,所以需要合理分配。

如果master服務器發生故障,就需要一個slave服務器轉變爲master服務器,同時將其他slave服務器連接到這個新的master服務器上,並遷移掛載的客戶端。

Redis的哨兵

主從複製如果發生了故障,雖然我們知道了大概的處理方式,但是這個故障轉移並不是自動解決的,我們需要監控節點,並且手動轉移。或者也可以使用腳本來實現。

但是redis提供了redis sentinel(哨兵)來解決了主從複製中故障轉移的功能。sentinel是一個特殊的redis,並不存儲數據,主要是去監控節點是否有故障,實現自動轉移故障,通知其他哨兵和客戶端

一套sentinel可以監控多套master-slave架構

當多個sentinel發現了master有故障,sentinel之間會選舉出一個sentinel領導,可以把他看作一個客戶端來處理故障。然後從slave中選出一個合適的slave作爲new_master,然後通知其他slave和客戶端哪個節點是new_master。如果old_master重啓後,會將其作爲slave節點去連接new_master

哨兵啓動:redis-sentinel sentinel-端口.conf

配置文件關鍵屬性

  • port 端口,默認26379
  • sentinel monitor <masterName> <masterip> <masterport> <quorum> 表示該sentinel監視哪一個master,當sentinel認定某個redis節點故障的個數超過quorum,就下線該節點
  • sentinel down-after-millseconds <masterName> <timeout> 多少時間內master沒有響應就認爲master故障
  • sentinel parallel-syncs <masterName> <numreplicas> 一次允許最多可以有多少同步操作,越多同步速率越快,服務器壓力越大
  • sentinel failover-timeout <masterName> <timeout> 同步超時時間

sentinel不需要配置監控slave節點,只需要通過主節點分析主從關係,就能實現監控slave節點

節點數量應該>=3,且最好是奇數,這是爲了保證公平以及能夠快速選舉出唯一領導者。

監控節點

sentinel最開始會向master發送info命令,再根據當前master的主從關係,去向它的slave發送info,之後每10秒會向master和slave發送一次info指令

  1. 通過對master進行info命令可以獲取到:master信息和狀態,slave節點地址
  2. 然後對slave節點info命令獲取到slave狀態和屬性

新加入的sentinel發現master已經有過sentinel節點監視了,就通過master節點的channel進行發佈訂閱來加入其他sentinel節點。

每隔2秒每個sentinel節點通過sentinel:hello頻道,交互自身信息和其他sentinel節點獲取的信息,這樣sentinel節點之間可以快速“溝通”,信息同步的速度就很快。

同時每1秒,每個sentinel節點會對其他的sentinel節點和redis節點執行Ping指令,進行心跳檢測,判斷節點是否在線。

發現故障

根據之前的配置,一個sentinel發現某個master節點響應超時了,就會進行主觀下線標記。然後在sentinel之間發送命令:sentinel is-master-down-by-addr詢問其他的sentinel節點判斷一下是否進行客觀下線,並且準備選舉。

  • 主觀下線:S_DOWN,這是一個sentinel節點對該redis節點的“主觀”判斷,可能由於當前sentinel的網絡等原因,和redis節點的連接超時了,所以只有該sentinel個人認爲redis節點下線了。
  • 客觀下線:O_DOWN,當其他sentinel節點對該redis節點達成共識(超過quorum數量的sentinel都認爲redis節點下線了)

故障轉移

根據之前提到了,我們要從sentinel節點中選舉出一個領導者,由領導者來完成故障轉移,領導者會從slave節點中選擇合適的節點作爲master節點,讓其他slave節點同步新的master節點

sentinel領導者選舉

每個做完主觀下線的sentinel節點會發送sentinel is-master-down-by-addr命令,希望成爲領導者。

  • 此時收到命令的sentinel節點如果沒有投票給其他sentinel節點,就會同意這次投票(即每個節點只有一次投票機會,先到先得)。
  • 當某個sentinel節點的票數超過半數,並且超過了quorum時,就由該節點作爲領導節點來執行故障轉移。
  • 如果投票中,出現多個領導者就會重新選舉,投票輪數+1,保證只有唯一領導者。

選擇合適的slave節點

sentinel領導節點會先從在線的slave節點中選擇合適的slave節點,將設置爲新的master節點,篩選的條件如下:

  1. 先根據響應速度和最早與master斷連的節點中篩選。
  2. 然後判斷優先級,選擇slave節點優先級(slave-priority)最高的,通常默認一致,可以選擇給硬件配置更好的slave節點設立更高的優先級。存在就返回,不存在就繼續篩選。
  3. 再根據slave節點的offset,選擇偏移量最大的節點(複製的數據最完整)。存在就返回,不存在就繼續篩選。
  4. 選擇最先啓動的slave節點。

故障轉移

  1. 領導者選出最合適的slave節點後,使其執行slave of no one命令成爲master
  2. 讓剩下的slave節點執行slaveof new_master ip port,變成new_master的slave
  3. 從new_master節點同步數據(每次能同步的slave數量和parallel-syncs參數有關)
  4. 將old_master設置爲new_master的slave並監視,再次上線時,就讓該節點去同步new_master的數據
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章