應用端調用
Master可能會因爲某些情況宕機了,如果在客戶端是固定一個地址去訪問,肯定是不合理的,所以客戶端請求是請求哨兵,從哨兵獲取主機地址的信息,或者是從機的信息。可以實現一個例子
1、隨機選擇一個哨兵連接,獲取主機、從機信息
2、模擬客戶端定時訪問,實現簡單輪訓效果,輪訓從節點
3、連接失敗重試訪問
$sentinelConf=[//這裏是哨兵信息的集合 ['ip'=>"192.168.1.14",'port'=>"26379"], ['ip'=>"192.168.1.15",'port'=>"26379"], ['ip'=>"192.168.1.16",'port'=>"26379"], ]; $index = array_rand($sentinelConf);//隨機獲取一個哨兵信息,當然輪詢啊什麼的其他算法獲取也可以 $info = $sentinelConf[$index]; try{ $redis = new Redis(); $redis->connect($info['ip'],$info['port']); $slaveInfo = $redis->rawCommand("sentinel","slaves","mymaster");//找到所有mymaster的從節點信息 //$slaveInfo = $redis->rawCommand("sentinel","master","mymaster");//找到mymaster的主節點信息 var_dump($slaveInfo); }catch (\Exception $e){ //鏈接失敗重新選擇哨兵 }
Sentinel 實現原理
1.檢測問題,主要講的是三個定時任務,這三個內部的執行任務可以保證出現問題馬上讓 Sentinel 知道。
2.發現問題,主要講的是主觀下線和客觀下線。當有一臺 Sentinel 機器發現問題時,它就會主觀對它主觀下線。但是當多個 Sentinel 都發現有問題的時候,纔會出現客觀下線。
3.找到解決問題的人,主要講的是領導者選舉,如何在 Sentinel 內部多臺節點做領導者選舉,選出一個領導者。
4.解決問題,主要講的是故障轉移,即如何進行故障轉移。
三個定時任務
1.每10秒每個 Sentinel 對 Master 和 Slave 執行一次 Info Replication (也就是去更新主從節點的信息)
2.每2秒每個 Sentinel 通過 Master 節點的 channel 交換信息(pub/sub)(sentinel是通過master節點建立信息交換的,之後就會有其他哨兵和主從的信息)
3.每1秒每個 Sentinel 對其他 Sentinel 和 Redis 執行 ping 。
第一個定時任務,指的是 Redis Sentinel 可以對 Redis 節點做失敗判斷和故障轉移,在 Redis 內部有三個定時任務作爲基礎,來 Info Replication 發現Slave 節點,這個命令可以確定主從關係。
第兩個定時任務,類似於發佈訂閱, Sentinel 會對主從關係進行判定,通過 _sentinel_:hello 頻道交互。瞭解主從關係可以幫助更好的自動化操作 Redis
。然後 Sentinel 會告知系統消息給其它 Sentinel 節點,最終達到共識,同時 Sentinel 節點能夠互相感知到對方。
第三個定時任務,指的是對每個節點和其它 Sentinel 進行心跳檢測,它是失敗判定的依據。
主觀下線和客觀下線
sentinel monitor mymaster 127.0.0.1 6379 2 #當至少2個哨兵覺得故障纔是真故障
sentinel down-after-milliseconds mymaster 30000 #請求超時毫秒
主觀下線:每個 Sentinel 節點對 Redis 節點失敗的“偏見”。之所以是偏見,只是因爲某一臺機器30秒內沒有得到回覆。
客觀下線:這個時候需要所有 Sentinel 節點都發現它30秒內無回覆,纔會達到共識。
領導者選舉方式
1.每個做主觀下線的sentinel節點,會向其他的sentinel節點發送命令,要求將它設置成爲領導者
2.收到命令sentinel節點,如果沒有同意通過其它節點發送的命令,那麼就會同意請求,否則就會拒絕
3.如果sentinel節點發現自己票數超過半數,同時也超過了 sentinel monitor mymaster 127.0.0.1 6379 2 超過2個的時候,就會成爲領導者
4.進行故障轉移操作
如何選擇“合適的”Slave 節點
Redis 內部其實是有一個優先級配置的,在配置文件中 slave-priority ,這個參數是 Salve 節點的優先級配置,如果存在則返回,如果不存在則繼續。
當上面這個優先級不滿足的時候, Redis 還會選擇複製偏移量最大的 Slave節點,如果存在則返回,如果不存在則繼續。之所以選擇偏移量最大,這是因爲偏移量越小,和 Master 的數據越不接近,現在 Master 掛掉了,說明這個偏移量小的機器數據也可能存在問題,這就是爲什麼要選偏移量最大的 Slave 的原因。如果發現偏移量都一樣,這個時候 Redis 會默認選擇 runid 最小的節點。
生產環境中部署技巧
1)Sentinel 節點不應該部署在一臺物理“機器”上。
這裏特意強調物理機是因爲一臺物理機做成了若干虛擬機或者現今比較流行的容器,它們雖然有不同的 ** IP ** 地址,但實際上它們都是同一臺物理機,同一臺物理機意味着如果這臺機器有什麼硬件故障,所有的虛擬機都會受到影響,爲了實現 Sentinel 節點集合真正的高可用,請勿將 ** Sentinel **節點部署在同一臺物理機器上。
2)部署至少三個且奇數個的 Sentinel 節點。
3) 以上是通過增加 Sentinel 節點的個數提高對於故障判定的準確性,因爲領導者選舉需要至少一半加1個節點。奇數個節點可以在滿足該條件的基礎上節省一個節點。
哨兵常見問題
哨兵集羣在發現 master node 掛掉後會進行故障轉移,也就是啓動其中一個 slave node 爲 master node 。在這過程中,可能會導致數據丟失的情況。
1、異步複製導致數據丟失
因爲master->slave的複製是異步,所以可能有部分還沒來得及複製到slave就宕機了,此時這些部分數據就丟失了。
2、集羣腦裂導致數據丟失
腦裂,也就是說,某個master所在機器突然脫離了正常的網絡,跟其它slave機器不能連接,但是實際上master還運行着。這個情況就有可能出現兩臺master,也就有可能會有新數據寫入舊master導致數據丟失
造成問題:此時哨兵可能就會認爲master宕機了,然後開始選舉,將其它 slave 切換成 master 。這時候集羣裏就會有2個 master ,也就是所謂的腦裂。此時雖然某個 slave 被切換成了 master ,但是可能client還沒來得及切換成新的 master ,還繼續寫向舊的 master 的數據可能就丟失了。
因此舊master再次恢復的時候,會被作爲一個 slave 掛到新的 master 上去,自己的數據會被清空,重新從新的 master 複製數據。
如何解決:
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1個slave,數據複製和同步的延遲不能超過10秒。如果說一旦所有的slave,數據複製和同步的延遲都超過了10秒鐘,那麼這個時候,master就不會再接收任何請求了
1、異步複製導致的數據丟失
在異步複製的過程當中,通過 min-slaves-max-lag 這個配置,就可以確保的說,一旦 slave 複製數據和 ack 延遲時間太長,就認爲可能 master 宕機後損失的數據太多了,那麼就拒絕寫請求,這樣就可以把master宕機時由於部分數據未同步到 slave 導致的數據丟失降低到可控範圍內
2、集羣腦裂導致的數據丟失
集羣腦裂因爲 client 還沒來得及切換成新的 master ,還繼續寫向舊的 master 的數據可能就丟失了通過 min-slaves-to-write 確保必須是有多少個從節點連接,並且延遲時間小於 min-slaves-max-lag 多少秒。
對於 client 來講,就需要做些處理,比如先將數據緩存到內存當中,然後過一段時間處理,或者連接失敗,接收到錯誤切換新的 master 處理。
redis sentinel日誌參數說明
以下列出的是客戶端可以通過訂閱來獲得的頻道和信息的格式: 第一個英文單詞是頻道/事件的名字, 其餘的是數據的格式。 注意, 當格式中包含 instance details 字樣時, 表示頻道所返回的信息中包含了以下用於識別目標實例的內容:
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@ 字符之後的內容用於指定主服務器, 這些內容是可選的, 它們僅在 @ 字符之前的內容指定的實例不是主服務器時使用。
· +reset-master <instance details>:主服務器已被重置。
· +slave <instance details>:一個新的從服務器已經被 Sentinel 識別並關聯。
· +failover-state-reconf-slaves <instance details>:故障轉移狀態切換到了 reconf-slaves 狀態。
· +failover-detected <instance details>:另一個 Sentinel 開始了一次故障轉移操作,或者一個從服務器轉換成了主服務器。
· +slave-reconf-sent <instance details>:領頭(leader)的 Sentinel 向實例發送了 SLAVEOF 命令,爲實例設置新的主服務器。
· +slave-reconf-inprog <instance details>:實例正在將自己設置爲指定主服務器的從服務器,但相應的同步過程仍未完成。
· +slave-reconf-done <instance details>:從服務器已經成功完成對新主服務器的同步。
· -dup-sentinel <instance details>:對給定主服務器進行監視的一個或多個 Sentinel 已經因爲重複出現而被移除 —— 當 Sentinel 實例重啓的時候,就會出現這種情況。
· +sentinel <instance details>:一個監視給定主服務器的新 Sentinel 已經被識別並添加。
· +sdown <instance details>:給定的實例現在處於主觀下線狀態。
· -sdown <instance details>:給定的實例已經不再處於主觀下線狀態。
· +odown <instance details>:給定的實例現在處於客觀下線狀態。
· -odown <instance details>:給定的實例已經不再處於客觀下線狀態。
· +new-epoch <instance details>:當前的紀元(epoch)已經被更新。
· +try-failover <instance details>:一個新的故障遷移操作正在執行中,等待被大多數 Sentinel 選中(waiting to be elected by the majority)。
· +elected-leader <instance details>:贏得指定紀元的選舉,可以進行故障遷移操作了。
+failover-state-select-slave <instance details>:故障轉移操作現在處於 select-slave 狀態 —— Sentinel 正在尋找可以升級爲主服務器的從服務器。
· no-good-slave <instance details>:Sentinel 操作未能找到適合進行升級的從服務器。Sentinel 會在一段時間之後再次嘗試尋找合適的從服務器來進行升級,又或者直接放棄執行故障轉移操作。
· selected-slave <instance details>:Sentinel 順利找到適合進行升級的從服務器。
· failover-state-send-slaveof-noone <instance details>:Sentinel 正在將指定的從服務器升級爲主服務器,等待升級功能完成。
· failover-end-for-timeout <instance details>:故障轉移因爲超時而中止,不過最終所有從服務器都會開始複製新的主服務器(slaves will eventually be configured to replicate with the new master anyway)。
· failover-end <instance details>:故障轉移操作順利完成。所有從服務器都開始複製新的主服務器了。
· +switch-master <master name> <oldip> <oldport> <newip> <newport>:配置變更,主服務器的 IP 和地址已經改變。 這是絕大多數外部用戶都關心的信息。