淺談:redis的主從複製 + 哨兵模式
主從模式
在談論redis的主從複製之前,我們先回想下mysql的主從搭建過程,第一步呢首先要在主庫伺服器中修改my.cnf,開啟一下bin_log功能,設定下server-id=1,重啟服務後開啟一個主從的授權,然後就可以show master status檢視主庫的狀態記錄下主庫的master_log_file和master_log_pos;第二步呢就是修改從庫的server-id為2(有其餘從庫依次3,4····),開啟relay_log,重啟從庫後,設定與master主庫連線的命令,開啟slave使從庫生效。。這個mysql主從搭建的過程還是相對比較複雜的,而且要想實時災備和主從切換,還得需要配置一些其他的,比如借用MHA架構。但是呢,redis的主從搭建就十分簡單了。
redis主從搭建過程:
- 主redis伺服器什麼也不需要修改,擺那啟動就好。
- 從機伺服器在redis.conf檔案里加上:
replicaof 主機ip:port埠號
,啟動就好了。
redis主從實現的原理:
- slave從機在配置完啟動後,會根據配置的主機的ip:port去ping主機,看能不能ping通,建立一個socket通道。期間也會不斷的進行心跳檢測,保證二者實時感應到的。
- socket通道建立後,slave經歷過一系列的鑑權檢驗沒問題後,它會在master那裡獲得一個RDB快照檔案,由於它是二進位制檔案,所以體積小,傳輸過程也比較快。slave會解析這個RDB檔案,將那個快照版本的資料複製到自己的伺服器上,這是一個全量複製的過程。
- 接下來如果master再接收到來自於客戶端的其他命令,它會直接將命令傳播給slave,而slave會一直的去接收並執行主伺服器master傳遞過來的命令,這是一個增量複製的過程。
下面我畫一張示意圖來描述這個過程:
至於redis為什麼要做主從搭建,這也源於主從搭建的兩個優點:
- 資料容災。從機作為主機的一個資料備份,當主機當機後,從機能夠快速的切換成主機,達到一個高可用的目的。這也是redis主從搭建的常用使用場景。
- 讀寫分離。主機負責寫資料,從機負責讀資料,提高redis的吞吐量,但是會發生資料一致性的問題,畢竟主從同步資料需要時間。
需要注意的是:
- 當redis搭建主從後,從機就只能讀資料,不能去寫資料了,寫的話會報錯。
- 單純的搭建redis主從,不能實現主從的切換,也就是主機當機後,從機還是從機,要想實現主從切換,必須引用redis的哨兵機制。
哨兵模式
哨兵二字可以讓我們聯想到監察員一類的職務,它的角色在應該是來監控我們的redis主從服務,當發現我們的redis主從服務出現問題了,比如主機下線了一類的,它就要發揮它的作用,將其他的從機扶持成主機,達到系統正常執行的效果。
一般而言,我們會用多個例項來組成sentinel叢集(哨兵叢集)來監視一組的一主多從或者是多組的一主多從。在這裡提一句,哨兵模式也遵循一個選舉機制和過半原則,只有當一半以上的sentinel認為某臺機器出問題了,這個決議才會被通過進行之後的操作。
哨兵模式的部署示意圖:
關於哨兵模式的搭建過程本文不再綴敘了,百度上很多都寫過類似的部落格,可以參考:https://www.cnblogs.com/qinxu/p/9633418.html
執行流程
啟動並初始化Sentinel
Sentinel是一個特殊的redis伺服器,不會去進行持久化,Sentinel例項啟動後,每個Sentinel會建立2個連向主伺服器的網路連線。
- 命令連線:用於向主伺服器傳送命令,並接收響應
- 訂閱連線:用於訂閱主伺服器的一個sentinel:hello頻道
獲取主伺服器資訊
Sentinel預設每10秒一次,向被監控的主伺服器傳送info命令,獲取主伺服器和其下屬從伺服器的資訊。
獲取從伺服器資訊
當sentinel發現主伺服器有新的從伺服器出現時,sentinel還會向從伺服器簡歷命令連線,當命令連線建立之後,sentinel還是會預設10s一次,向從伺服器傳送info命令,並記錄從伺服器的資訊。
向主伺服器和從伺服器傳送訊息(以訂閱的方式)
預設情況下,sentinel每2秒一次,向所有被監視的主伺服器和從伺服器所訂閱的sentinel:hello頻道上傳送訊息,訊息會攜帶sentinel自身的資訊和主伺服器的資訊。
接收來自主伺服器和從伺服器的頻道資訊
當sentinel與主伺服器或者從伺服器建立起訂閱連線之後,sentinel就會通過訂閱連線,向伺服器傳送以下命令:
subscribe —sentinel—:hello
sentinel彼此之間只建立命令連線,而不建立訂閱連線。因為sentinel通過訂閱主伺服器或者從伺服器,就能夠感知到新的sentinel的加入,而一旦新的sentinel加入後,相互感知的sentinel通過命令連線來通訊就好了。
檢測主觀下線狀態
Sentinel每秒一次向所有與它建立了命令連線的例項(主伺服器、從伺服器和其他Sentinel)傳送PING命
令
例項在down-after-milliseconds毫秒內返回無效回覆(除了+PONG、-LOADING、-MASTERDOWN外)
例項在down-after-milliseconds毫秒內無回覆(超時)
Sentinel就會認為該例項主觀下線(SDown)
檢查客觀下線狀態
當一個Sentinel將一個主伺服器判斷為主觀下線後,Sentinel會向同時監控這個主伺服器的所有其他Sentinel傳送查詢命令
SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> <runid>
其他Sentinel回覆
<down_state>< leader_runid >< leader_epoch >
判斷它們是否也認為主伺服器下線。如果達到Sentinel配置中的quorum數量的Sentinel例項都判斷主伺服器為主觀下線,則該主伺服器就會被判定為客觀下線(ODown)。
選舉Leader Sentinel
當一個主伺服器被判定為客觀下線後,監視這個主伺服器的所有Sentinel會通過選舉演算法(raft),選出一個Leader Sentinel去執行failover(故障轉移)操作。
故障轉移的步驟:
- 它會將失效 Master 的其中一個 Slave 升級為新的 Master , 並讓失效 Master 的其他 Slave 改為複製新的 Master ;
- 當客戶端試圖連線失效的 Master 時,叢集也會向客戶端返回新 Master 的地址,使得叢集可以使用現在的 Master 替換失效 Master 。
- Master 和 Slave 伺服器切換後, Master 的 redis.conf 、 Slave 的 redis.conf 和
sentinel.conf 的配置檔案的內容都會發生相應的改變,即, Master 主伺服器的redis.conf配置檔案中會多一行 replicaof 的配置, sentinel.conf 的監控目標會隨之調換。
主伺服器master的選擇規則
- 過濾掉主觀下線的節點
- 選擇slave-priority最高的節點,如果由則返回沒有就繼續選擇
- 選擇出複製偏移量最大的系節點,因為複製偏移量越大則資料複製的越完整,如果由就返回了,沒有就繼續
- 選擇run_id最小的節點,因為run_id越小說明重啟次數越少