複製粘貼自: http://www.javashuo.com/article/p-zevxoujd-gu.html 請點擊此連接查看原文.
html
僅供本人學習參考, 若有侵權, 請聯繫刪除, 多謝!java
Redis的集羣方案大體有三種:1)redis cluster集羣方案;2)master/slave主從方案;3)哨兵模式來進行主從替換以及故障恢復。node
1、sentinel哨兵模式介紹
Sentinel(哨兵)是用於監控redis集羣中Master狀態的工具,是Redis 的高可用性解決方案,sentinel哨兵模式已經被集成在redis2.4以後的版本中。sentinel是redis高可用的解決方案,sentinel系統能夠監視一個或者多個redis master服務,以及這些master服務的全部從服務;當某個master服務下線時,自動將該master下的某個從服務升級爲master服務替代已下線的master服務繼續處理請求。python
sentinel可讓redis實現主從複製,當一個集羣中的master失效以後,sentinel能夠選舉出一個新的master用於自動接替master的工做,集羣中的其餘redis服務器自動指向新的master同步數據。通常建議sentinel採起奇數臺,防止某一臺sentinel沒法鏈接到master致使誤切換。其結構以下:linux
Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis作Master-slave的高可用方案時,假如master宕機了,Redis自己(包括它的不少客戶端)都沒有實現自動進行主備切換,而Redis-sentinel自己也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自動切換。Sentinel由一個或多個Sentinel 實例 組成的Sentinel 系統能夠監視任意多個主服務器,以及這些主服務器屬下的全部從服務器,並在被監視的主服務器進入下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器。redis
例以下圖所示:算法
在Server1 掉線後:spring
升級Server2 爲新的主服務器:shell
Sentinel版本
Sentinel當前最新的穩定版本稱爲Sentinel 2(與以前的Sentinel 1區分開來)。隨着redis2.8的安裝包一塊兒發行。安裝完Redis2.8後,能夠在redis2.8/src/裏面找到Redis-sentinel的啓動程序。
強烈建議:若是你使用的是redis2.6(sentinel版本爲sentinel 1),你最好應該使用redis2.8版本的sentinel 2,由於sentinel 1有不少的Bug,已經被官方棄用,因此強烈建議使用redis2.8以及sentinel 2。數據庫
Sentinel狀態持久化
snetinel的狀態會被持久化地寫入sentinel的配置文件中。每次當收到一個新的配置時,或者新建立一個配置時,配置會被持久化到硬盤中,並帶上配置的版本戳。這意味着,能夠安全的中止和重啓sentinel進程。
Sentinel做用:
1)Master狀態檢測
2)若是Master異常,則會進行Master-Slave切換,將其中一個Slave做爲Master,將以前的Master做爲Slave。
3)Master-Slave切換後,master_redis.conf、slave_redis.conf和sentinel.conf的內容都會發生改變,即master_redis.conf中會多一行slaveof的配置,sentinel.conf的監控目標會隨之調換。
Sentinel工做方式(每一個Sentinel實例都執行的定時任務)
1)每一個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其餘 Sentinel 實例發送一個PING命令。
2)若是一個實例(instance)距離最後一次有效回覆PING命令的時間超過 own-after-milliseconds 選項所指定的值,則這個實例會被Sentinel標記爲主觀下線。
3)若是一個Master被標記爲主觀下線,則正在監視這個Master的全部 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。
4)當有足夠數量的Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態,則Master會被標記爲客觀下線。
5)在通常狀況下,每一個Sentinel 會以每10秒一次的頻率向它已知的全部Master,Slave發送 INFO 命令。
6)當Master被Sentinel標記爲客觀下線時,Sentinel 向下線的 Master 的全部Slave發送 INFO命令的頻率會從10秒一次改成每秒一次。
7)若沒有足夠數量的Sentinel贊成Master已經下線,Master的客觀下線狀態就會被移除。 若 Master從新向Sentinel 的PING命令返回有效回覆,Master的主觀下線狀態就會被移除。
三個定時任務
sentinel在內部有3個定時任務
1)每10秒每一個sentinel會對master和slave執行info命令,這個任務達到兩個目的:
a)發現slave節點
b)確認主從關係
2)每2秒每一個sentinel經過master節點的channel交換信息(pub/sub)。master節點上有一個發佈訂閱的頻道(__sentinel__:hello)。sentinel節點經過__sentinel__:hello頻道進行信息交換(對節點的"見解"和自身的信息),達成共識。
3)每1秒每一個sentinel對其餘sentinel和redis節點執行ping操做(相互監控),這個實際上是一個心跳檢測,是失敗斷定的依據。
主觀下線
所謂主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個Sentinel實例對服務器作出的下線判斷,即單個sentinel認爲某個服務下線(有多是接收不到訂閱,之間的網絡不通等等緣由)。
主觀下線就是說若是服務器在down-after-milliseconds給定的毫秒數以內, 沒有返回 Sentinel 發送的 PING 命令的回覆, 或者返回一個錯誤, 那麼 Sentinel 將這個服務器標記爲主觀下線(SDOWN )。
sentinel會以每秒一次的頻率向全部與其創建了命令鏈接的實例(master,從服務,其餘sentinel)發ping命令,經過判斷ping回覆是有效回覆,仍是無效回覆來判斷實例時候在線(對該sentinel來講是「主觀在線」)。
sentinel配置文件中的down-after-milliseconds設置了判斷主觀下線的時間長度,若是實例在down-after-milliseconds毫秒內,返回的都是無效回覆,那麼sentinel回認爲該實例已(主觀)下線,修改其flags狀態爲SRI_S_DOWN。若是多個sentinel監視一個服務,有可能存在多個sentinel的down-after-milliseconds配置不一樣,這個在實際生產中要注意。
客觀下線
客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 實例在對同一個服務器作出 SDOWN 判斷, 而且經過 SENTINEL is-master-down-by-addr 命令互相交流以後, 得出的服務器下線判斷,而後開啓failover。
客觀下線就是說只有在足夠數量的 Sentinel 都將一個服務器標記爲主觀下線以後, 服務器纔會被標記爲客觀下線(ODOWN)。
只有當master被認定爲客觀下線時,纔會發生故障遷移。
當sentinel監視的某個服務主觀下線後,sentinel會詢問其它監視該服務的sentinel,看它們是否也認爲該服務主觀下線,接收到足夠數量(這個值能夠配置)的sentinel判斷爲主觀下線,既任務該服務客觀下線,並對其作故障轉移操做。
sentinel經過發送 SENTINEL is-master-down-by-addr ip port current_epoch runid,(ip:主觀下線的服務id,port:主觀下線的服務端口,current_epoch:sentinel的紀元,runid:*表示檢測服務下線狀態,若是是sentinel 運行id,表示用來選舉領頭sentinel)來詢問其它sentinel是否贊成服務下線。
一個sentinel接收另外一個sentinel發來的is-master-down-by-addr後,提取參數,根據ip和端口,檢測該服務時候在該sentinel主觀下線,而且回覆is-master-down-by-addr,回覆包含三個參數:down_state(1表示已下線,0表示未下線),leader_runid(領頭sentinal id),leader_epoch(領頭sentinel紀元)。
sentinel接收到回覆後,根據配置設置的下線最小數量,達到這個值,既認爲該服務客觀下線。
客觀下線條件只適用於主服務器: 對於任何其餘類型的 Redis 實例, Sentinel 在將它們判斷爲下線前不須要進行協商, 因此從服務器或者其餘 Sentinel 永遠不會達到客觀下線條件。只要一個 Sentinel 發現某個主服務器進入了客觀下線狀態, 這個 Sentinel 就可能會被其餘 Sentinel 推選出, 並對失效的主服務器執行自動故障遷移操做。
在redis-sentinel的conf文件裏有這麼兩個配置:
1)sentinel monitor <masterName> <ip> <port> <quorum>
四個參數含義:
masterName這個是對某個master+slave組合的一個區分標識(一套sentinel是能夠監聽多套master+slave這樣的組合的)。
ip 和 port 就是master節點的 ip 和 端口號。
quorum這個參數是進行客觀下線的一個依據,意思是至少有 quorum 個sentinel主觀的認爲這個master有故障,纔會對這個master進行下線以及故障轉移。由於有的時候,某個sentinel節點可能由於自身網絡緣由,致使沒法鏈接master,而此時master並無出現故障,因此這就須要多個sentinel都一致認爲該master有問題,才能夠進行下一步操做,這就保證了公平性和高可用。
2)sentinel down-after-milliseconds <masterName> <timeout>
這個配置其實就是進行主觀下線的一個依據,masterName這個參數不用說了,timeout是一個毫秒值,表示:若是這臺sentinel超過timeout這個時間都沒法連通master包括slave(slave不須要客觀下線,由於不須要故障轉移)的話,就會主觀認爲該master已經下線(實際下線須要客觀下線的判斷經過纔會下線)
那麼,多個sentinel之間是如何達到共識的呢?
這就是依賴於前面說的第二個定時任務,某個sentinel先將master節點進行一個主觀下線,而後會將這個斷定經過sentinel is-master-down-by-addr這個命令問對應的節點是否也一樣認爲該addr的master節點要作客觀下線。最後當達成這一共識的sentinel個數達到前面說的quorum設置的這個值時,就會對該master節點下線進行故障轉移。quorum的值通常設置爲sentinel個數的二分之一加1,例如3個sentinel就設置2。
主觀下線(SDOWN)和客觀下線(ODOWN)的更多細節
sentinel對於不可用有兩種不一樣的見解,一個叫主觀不可用(SDOWN),另一個叫客觀不可用(ODOWN)。SDOWN是sentinel本身主觀上檢測到的關於master的狀態,ODOWN須要必定數量的sentinel達成一致意見才能認爲一個master客觀上已經宕掉,各個sentinel之間經過命令SENTINEL is_master_down_by_addr來得到其它sentinel對master的檢測結果。
從sentinel的角度來看,若是發送了PING心跳後,在必定時間內沒有收到合法的回覆,就達到了SDOWN的條件。這個時間在配置中經過is-master-down-after-milliseconds參數配置。
當sentinel發送PING後,如下回復之一都被認爲是合法的:
PING replied with +PONG.
PING replied with -LOADING error.
PING replied with -MASTERDOWN error.
其它任何回覆(或者根本沒有回覆)都是不合法的。
從SDOWN切換到ODOWN不須要任何一致性算法,只須要一個gossip協議:若是一個sentinel收到了足夠多的sentinel發來消息告訴它某個master已經down掉了,SDOWN狀態就會變成ODOWN狀態。若是以後master可用了,這個狀態就會相應地被清理掉。
正如以前已經解釋過了,真正進行failover須要一個受權的過程,可是全部的failover都開始於一個ODOWN狀態。
ODOWN狀態只適用於master,對於不是master的redis節點sentinel之間不須要任何協商,slaves和sentinel不會有ODOWN狀態。
配置版本號
爲何要先得到大多數sentinel的承認時才能真正去執行failover呢?
當一個sentinel被受權後,它將會得到宕掉的master的一份最新配置版本號,當failover執行結束之後,這個版本號將會被用於最新的配置。由於大多數sentinel都已經知道該版本號已經被要執行failover的sentinel拿走了,因此其餘的sentinel都不能再去使用這個版本號。這意味着,每次failover都會附帶有一個獨一無二的版本號。咱們將會看到這樣作的重要性。並且,sentinel集羣都遵照一個規則:若是sentinel A推薦sentinel B去執行failover,B會等待一段時間後,自行再次去對同一個master執行failover,這個等待的時間是經過failover-timeout配置項去配置的。從這個規則能夠看出,sentinel集羣中的sentinel不會再同一時刻併發去failover同一個master,第一個進行failover的sentinel若是失敗了,另一個將會在必定時間內進行從新進行failover,以此類推。
redis sentinel保證了活躍性:若是大多數sentinel可以互相通訊,最終將會有一個被受權去進行failover.
redis sentinel也保證了安全性:每一個試圖去failover同一個master的sentinel都會獲得一個獨一無二的版本號。
配置傳播
一旦一個sentinel成功地對一個master進行了failover,它將會把關於master的最新配置經過廣播形式通知其它sentinel,其它的sentinel則更新對應master的配置。
一個faiover要想被成功實行,sentinel必須可以向選爲master的slave發送SLAVEOF NO ONE命令,而後可以經過INFO命令看到新master的配置信息。
當將一個slave選舉爲master併發送SLAVEOF NO ONE後,即便其它的slave還沒針對新master從新配置本身,failover也被認爲是成功了的,而後全部sentinels將會發布新的配置信息。
新配在集羣中相互傳播的方式,就是爲何咱們須要當一個sentinel進行failover時必須被受權一個版本號的緣由。
每一個sentinel使用##發佈/訂閱##的方式持續地傳播master的配置版本信息,配置傳播的##發佈/訂閱##管道是:__sentinel__:hello。
由於每個配置都有一個版本號,因此以版本號最大的那個爲標準。
舉個例子:
假設有一個名爲mymaster的地址爲192.168.10.202:6379。一開始,集羣中全部的sentinel都知道這個地址,因而爲mymaster的配置打上版本號1。一段時候後mymaster死了,有一個sentinel被受權用版本號2對其進行failover。若是failover成功了,假設地址改成了192.168.10.202:9000,此時配置的版本號爲2,進行failover的sentinel會將新配置廣播給其餘的sentinel,因爲其餘sentinel維護的版本號爲1,發現新配置的版本號爲2時,版本號變大了,說明配置更新了,因而就會採用最新的版本號爲2的配置。
這意味着sentinel集羣保證了第二種活躍性:一個可以互相通訊的sentinel集羣最終會採用版本號最高且相同的配置。
sentinel的"仲裁會"
前面咱們談到,當一個master被sentinel集羣監控時,須要爲它指定一個參數,這個參數指定了當須要判決master爲不可用,而且進行failover時,所須要的sentinel數量,能夠稱這個參數爲票數
不過,當failover主備切換真正被觸發後,failover並不會立刻進行,還須要sentinel中的大多數sentinel受權後才能夠進行failover。
當ODOWN時,failover被觸發。failover一旦被觸發,嘗試去進行failover的sentinel會去得到「大多數」sentinel的受權(若是票數比大多數還要大的時候,則詢問更多的sentinel)
這個區別看起來很微妙,可是很容易理解和使用。例如,集羣中有5個sentinel,票數被設置爲2,當2個sentinel認爲一個master已經不可用了之後,將會觸發failover,可是,進行failover的那個sentinel必須先得到至少3個sentinel的受權才能夠實行failover。
若是票數被設置爲5,要達到ODOWN狀態,必須全部5個sentinel都主觀認爲master爲不可用,要進行failover,那麼得得到全部5個sentinel的受權。
選舉領頭sentinel(即領導者選舉)
一個redis服務被判斷爲客觀下線時,多個監視該服務的sentinel協商,選舉一個領頭sentinel,對該redis服務進行故障轉移操做。選舉領頭sentinel遵循如下規則:
1)全部的sentinel都有公平被選舉成領頭的資格。
2)全部的sentinel都有且只有一次將某個sentinel選舉成領頭的機會(在一輪選舉中),一旦選舉某個sentinel爲領頭,不能更改。
3)sentinel設置領頭sentinel是先到先得,一旦當前sentinel設置了領頭sentinel,之後要求設置sentinel爲領頭請求都會被拒絕。
4)每一個發現服務客觀下線的sentinel,都會要求其餘sentinel將本身設置成領頭。
5)當一個sentinel(源sentinel)向另外一個sentinel(目sentinel)發送is-master-down-by-addr ip port current_epoch runid命令的時候,runid參數不是*,而是sentinel運行id,就表示源sentinel要求目標sentinel選舉其爲領頭。
6)源sentinel會檢查目標sentinel對其要求設置成領頭的回覆,若是回覆的leader_runid和leader_epoch爲源sentinel,表示目標sentinel贊成將源sentinel設置成領頭。
7)若是某個sentinel被半數以上的sentinel設置成領頭,那麼該sentinel既爲領頭。
8)若是在限定時間內,沒有選舉出領頭sentinel,暫定一段時間,再選舉。
爲何要選領導者?
簡單來講,就是由於只能有一個sentinel節點去完成故障轉移。
sentinel is-master-down-by-addr這個命令有兩個做用,一是確認下線斷定,二是進行領導者選舉。
選舉過程:
1)每一個作主觀下線的sentinel節點向其餘sentinel節點發送上面那條命令,要求將它設置爲領導者。
2)收到命令的sentinel節點若是尚未贊成過其餘的sentinel發送的命令(還未投過票),那麼就會贊成,不然拒絕。
3)若是該sentinel節點發現本身的票數已通過半且達到了quorum的值,就會成爲領導者
4)若是這個過程出現多個sentinel成爲領導者,則會等待一段時間從新選舉。
Redis Sentinel的主從切換方案
Redis 2.8版開始正式提供名爲Sentinel的主從切換方案,通俗的來說,Sentinel能夠用來管理多個Redis服務器實例,能夠實現一個功能上實現HA的集羣,Sentinel主要負責三個方面的任務:
1)監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運做正常。
2)提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
3)自動故障遷移(Automatic failover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主服務器代替失效服務器。
Redis Sentinel 是一個分佈式系統, 能夠在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來接收關於主服務器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪一個從服務器做爲新的主服務器。
一個簡單的主從結構加sentinel集羣的架構圖以下:
上圖是一主一從節點,加上兩個部署了sentinel的集羣,sentinel集羣之間會互相通訊,溝通交流redis節點的狀態,作出相應的判斷並進行處理,這裏的主觀下線狀態和客觀下線狀態是比較重要的狀態,它們決定了是否進行故障轉移
能夠 經過訂閱指定的頻道信息,當服務器出現故障得時候通知管理員
客戶端能夠將 Sentinel 看做是一個只提供了訂閱功能的 Redis 服務器,你不可使用 PUBLISH 命令向這個服務器發送信息,但你能夠用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 經過訂閱給定的頻道來獲取相應的事件提醒。 一個頻道可以接收和這個頻道的名字相同的事件。 好比說, 名爲 +sdown 的頻道就能夠接收全部實例進入主觀下線(SDOWN)狀態的事件。
我的認爲,Sentinel實現的最主要的一個功能就是能作到自動故障遷移,即當某一個master掛了的時候,能夠自動的將某一個slave提高爲新的master,且原master的全部slave也都自動的將本身的master改成新提高的master,這樣咱們的程序的可用性大大提升了。只要redis安裝完成,Sentinel就安裝完成了,Sentinel集成在redis裏了。
Sentinel支持集羣(能夠部署在多臺機器上,也能夠在一臺物理機上經過多端口實現僞集羣部署)
很顯然,只使用單個sentinel進程來監控redis集羣是不可靠的,當sentinel進程宕掉後(sentinel自己也有單點問題,single-point-of-failure)整個集羣系統將沒法按照預期的方式運行。因此有必要將sentinel集羣,這樣有幾個好處:
1)即便有一些sentinel進程宕掉了,依然能夠進行redis集羣的主備切換;
2)若是隻有一個sentinel進程,若是這個進程運行出錯,或者是網絡堵塞,那麼將沒法實現redis集羣的主備切換(單點問題);
3)若是有多個sentinel,redis的客戶端能夠隨意地鏈接任意一個sentinel來得到關於redis集羣中的信息。
sentinel集羣注意事項
1)只有Sentinel 集羣中大多數服務器認定master主觀下線時master纔會被認定爲客觀下線,才能夠進行故障遷移,也就是說,即便無論咱們在sentinel monitor中設置的數是多少,就算是知足了該值,只要達不到大多數,就不會發生故障遷移。
2)官方建議sentinel至少部署三臺,且分佈在不一樣機器。這裏主要考慮到sentinel的可用性,假如咱們只部署了兩臺sentinel,且quorum設置爲1,也能夠實現自動故障遷移,但假如其中一臺sentinel掛了,就永遠不會觸發自動故障遷移,由於永遠達不到大多數sentinel認定master主觀下線了。
3)sentinel monitor配置中的master IP儘可能不要寫127.0.0.1或localhost,由於客戶端,如jedis獲取master是根據這個獲取的,若這樣配置,jedis獲取的ip則是127.0.0.1,這樣就可能致使程序鏈接不上master
4)當sentinel 啓動後會自動的修改sentinel.conf文件,如已發現的master的slave信息,和集羣中其它sentinel 的信息等,這樣即便重啓sentinel也能保持原來的狀態。注意,當集羣服務器調整時,如更換sentinel的機器,或者新配置一個sentinel,請不要直接複製原來運行過得sentinel配置文件,由於其裏面自動生成了以上說的那些信息,咱們應該複製一個新的配置文件或者把自動生成的信息給刪掉。
5)當發生故障遷移的時候,master的變動記錄與slave更換master的修改會自動同步到redis的配置文件,這樣即便重啓redis也能保持變動後的狀態。
每一個 Sentinel 都須要按期執行的任務
每一個 Sentinel 以每秒鐘一次的頻率向它所知的主服務器、從服務器以及其餘 Sentinel 實例發送一個 PING 命令。
若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 那麼這個實例會被 Sentinel 標記爲主觀下線。 一個有效回覆能夠是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
若是一個主服務器被標記爲主觀下線, 那麼正在監視這個主服務器的全部 Sentinel 要以每秒一次的頻率確認主服務器的確進入了主觀下線狀態。
若是一個主服務器被標記爲主觀下線, 而且有足夠數量的 Sentinel (至少要達到配置文件指定的數量)在指定的時間範圍內贊成這一判斷, 那麼這個主服務器被標記爲客觀下線。
在通常狀況下, 每一個 Sentinel 會以每 10 秒一次的頻率向它已知的全部主服務器和從服務器發送 INFO 命令。 當一個主服務器被 Sentinel 標記爲客觀下線時, Sentinel 向下線主服務器的全部從服務器發送 INFO 命令的頻率會從 10 秒一次改成每秒一次。
當沒有足夠數量的 Sentinel 贊成主服務器已經下線, 主服務器的客觀下線狀態就會被移除。 當主服務器從新向 Sentinel 的PING 命令返回有效回覆時, 主服務器的主管下線狀態就會被移除。
Sentinel之間和Slaves之間的自動發現機制
雖然sentinel集羣中各個sentinel都互相鏈接彼此來檢查對方的可用性以及互相發送消息。可是你不用在任何一個sentinel配置任何其它的sentinel的節點。由於sentinel利用了master的發佈/訂閱機制去自動發現其它也監控了統一master的sentinel節點。
經過向名爲__sentinel__:hello的管道中發送消息來實現。
一樣,你也不須要在sentinel中配置某個master的全部slave的地址,sentinel會經過詢問master來獲得這些slave的地址的。
每一個sentinel經過向每一個master和slave的發佈/訂閱頻道__sentinel__:hello每秒發送一次消息,來宣佈它的存在。
每一個sentinel也訂閱了每一個master和slave的頻道__sentinel__:hello的內容,來發現未知的sentinel,當檢測到了新的sentinel,則將其加入到自身維護的master監控列表中。
每一個sentinel發送的消息中也包含了其當前維護的最新的master配置。若是某個sentinel發現
本身的配置版本低於接收到的配置版本,則會用新的配置更新本身的master配置。
在爲一個master添加一個新的sentinel前,sentinel老是檢查是否已經有sentinel與新的sentinel的進程號或者是地址是同樣的。若是是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。
sentinel和redis身份驗證
當一個master配置爲須要密碼才能鏈接時,客戶端和slave在鏈接時都須要提供密碼。
master經過requirepass設置自身的密碼,不提供密碼沒法鏈接到這個master。
slave經過masterauth來設置訪問master時的密碼。
可是當使用了sentinel時,因爲一個master可能會變成一個slave,一個slave也可能會變成master,因此須要同時設置上述兩個配置項。
Sentinel API
在默認狀況下, Sentinel 使用 TCP 端口 26379 (普通 Redis 服務器使用的是 6379 )。Sentinel 接受 Redis 協議格式的命令請求, 因此你可使用 redis-cli 或者任何其餘 Redis 客戶端來與 Sentinel 進行通信。有兩種方式能夠和 Sentinel 進行通信:
1)是經過直接發送命令來查詢被監視 Redis 服務器的當前狀態, 以及 Sentinel 所知道的關於其餘 Sentinel 的信息, 諸如此類。
2)是使用發佈與訂閱功能, 經過接收 Sentinel 發送的通知: 當執行故障轉移操做, 或者某個被監視的服務器被判斷爲主觀下線或者客觀下線時, Sentinel 就會發送相應的信息。
Sentinel命令(即登陸到sentinel節點後執行的命令,好比執行"redis-cli -h 192.168.10.203 -p 26379"命令後,才能夠執行下面命令)
PING :返回 PONG 。
SENTINEL masters :列出全部被監視的主服務器,以及這些主服務器的當前狀態;
SENTINEL slaves <master name> :列出給定主服務器的全部從服務器,以及這些從服務器的當前狀態;
SENTINEL get-master-addr-by-name <master name> : 返回給定名字的主服務器的 IP 地址和端口號。 若是這個主服務器正在執行故障轉移操做, 或者針對這個主服務器的故障轉移操做已經完成, 那麼這個命令返回新的主服務器的 IP 地址和端口號;
SENTINEL reset <pattern> : 重置全部名字和給定模式 pattern 相匹配的主服務器。 pattern 參數是一個 Glob 風格的模式。 重置操做清楚主服務器目前的全部狀態, 包括正在執行中的故障轉移, 並移除目前已經發現和關聯的, 主服務器的全部從服務器和 Sentinel ;
SENTINEL failover <master name> : 當主服務器失效時, 在不詢問其餘 Sentinel 意見的狀況下, 強制開始一次自動故障遷移。 (不過發起故障轉移的 Sentinel 會向其餘 Sentinel 發送一個新的配置,其餘 Sentinel 會根據這個配置進行相應的更新)
SENTINEL MONITOR <name> <ip> <port> <quorum> 這個命令告訴sentinel去監聽一個新的master
SENTINEL REMOVE <name> 命令sentinel放棄對某個master的監聽
SENTINEL SET <name> <option> <value> 這個命令很像Redis的CONFIG SET命令,用來改變指定master的配置。支持多個<option><value>。例如如下實例:SENTINEL SET objects-cache-master down-after-milliseconds 1000
只要是配置文件中存在的配置項,均可以用SENTINEL SET命令來設置。這個還能夠用來設置master的屬性,好比說quorum(票數),而不須要先刪除master,再從新添加master。例如:SENTINEL SET objects-cache-master quorum 5
客戶端能夠經過SENTINEL get-master-addr-by-name <master name>獲取當前的主服務器IP地址和端口號,以及SENTINEL slaves <master name>獲取全部的Slaves信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
[root@redis-master ~]
# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role
role:slave
[root@redis-master ~]
# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role
role:slave
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role
role:master
登陸任意一個節點的sentinel,進行相關命令的操做(下面命令例子中的redisMaster是sentinel監控redis主從狀態時定義的master名稱)
1)sentinel masters 羅列全部sentinel 監視相關的master
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379
192.168.10.205:26379> sentinel masters
2)sentinel master masterName 列出一個master相關的的信息
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379
192.168.10.205:26379> sentinel master redisMaster
3)sentinel slaves masterName 列出一個master相應的slave組相關的數據
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379
192.168.10.205:26379> sentinel slaves redisMaster
4)sentinel sentinels masterName 列出master相關的sentinels組其餘相關的信息
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379
192.168.10.205:26379> sentinel sentinels redisMaster
5)sentinel get-master-addr-by-name masterName 獲取master-name相關的 ip addr 的信息
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379
192.168.10.205:26379> sentinel get-master-addr-by-name redisMaster
1)
"192.168.10.205"
2)
"6379"
|
增長或刪除Sentinel
因爲有sentinel自動發現機制,因此添加一個sentinel到你的集羣中很是容易,你所須要作的只是監控到某個Master上,而後新添加的sentinel就能得到其餘sentinel的信息以及master全部的slaves。
若是你須要添加多個sentinel,建議你一個接着一個添加,這樣能夠預防網絡隔離帶來的問題。你能夠每一個30秒添加一個sentinel。最後你能夠用SENTINEL MASTER mastername來檢查一下是否全部的sentinel都已經監控到了master。
刪除一個sentinel顯得有點複雜:由於sentinel永遠不會刪除一個已經存在過的sentinel,即便它已經與組織失去聯繫好久了。
要想刪除一個sentinel,應該遵循以下步驟:
1)中止所要刪除的sentinel
2)發送一個SENTINEL RESET * 命令給全部其它的sentinel實例,若是你想要重置指定master上面的sentinel,只須要把*號改成特定的名字,注意,須要一個接一個發,每次發送的間隔不低於30秒。
3)檢查一下全部的sentinels是否都有一致的當前sentinel數。使用SENTINEL MASTER mastername 來查詢。
刪除舊master或者不可達slave
sentinel永遠會記錄好一個Master的slaves,即便slave已經與組織失聯很久了。這是頗有用的,由於sentinel集羣必須有能力把一個恢復可用的slave進行從新配置。
而且,failover後,失效的master將會被標記爲新master的一個slave,這樣的話,當它變得可用時,就會重新master上覆制數據。
而後,有時候你想要永久地刪除掉一個slave(有可能它曾經是個master),你只須要發送一個SENTINEL RESET master命令給全部的sentinels,它們將會更新列表裏可以正確地複製master數據的slave。
發佈與訂閱信息(sentinel的日誌文件裏能夠看到這些信息)
客戶端能夠將 Sentinel 看做是一個只提供了訂閱功能的 Redis 服務器: 你不可使用 PUBLISH 命令向這個服務器發送信息, 但你能夠用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 經過訂閱給定的頻道來獲取相應的事件提醒。
一個頻道可以接收和這個頻道的名字相同的事件。 好比說, 名爲 +sdown 的頻道就能夠接收全部實例進入主觀下線(SDOWN)狀態的事件。
經過執行 "PSUBSCRIBE * "命令能夠接收全部事件信息(即訂閱全部消息)。
如下列出的是客戶端能夠經過訂閱來得到的頻道和信息的格式: 第一個英文單詞是頻道/事件的名字, 其他的是數據的格式。
注意, 當格式中包含 instance details 字樣時, 表示頻道所返回的信息中包含了如下用於識別目標實例的內容.
如下是全部能夠收到的消息的消息格式,若是你訂閱了全部消息的話。第一個單詞是頻道的名字,其它是數據的格式。
注意:如下的instance details的格式是:
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
若是這個redis實例是一個master,那麼@以後的消息就不會顯示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
+reset-master <instance details> -- 當master被重置時.
+slave <instance details> -- 當檢測到一個slave並添加進slave列表時.
+failover-state-reconf-slaves <instance details> -- Failover狀態變爲reconf-slaves狀態時
+failover-detected <instance details> -- 當failover發生時
+slave-reconf-sent <instance details> -- sentinel發送SLAVEOF命令把它從新配置時
+slave-reconf-inprog <instance details> -- slave被從新配置爲另一個master的slave,但數據複製還未發生時。
+slave-reconf-
done
<instance details> -- slave被從新配置爲另一個master的slave而且數據複製已經與master同步時。
-dup-sentinel <instance details> -- 刪除指定master上的冗餘sentinel時 (當一個sentinel從新啓動時,可能會發生這個事件).
+sentinel <instance details> -- 當master增長了一個sentinel時。
+sdown <instance details> -- 進入SDOWN狀態時;
-sdown <instance details> -- 離開SDOWN狀態時。
+odown <instance details> -- 進入ODOWN狀態時。
-odown <instance details> -- 離開ODOWN狀態時。
+new-epoch <instance details> -- 當前配置版本被更新時。
+try-failover <instance details> -- 達到failover條件,正等待其餘sentinel的選舉。
+elected-leader <instance details> -- 被選舉爲去執行failover的時候。
+failover-state-
select
-slave <instance details> -- 開始要選擇一個slave當選新master時。
no-good-slave <instance details> -- 沒有合適的slave來擔當新master
selected-slave <instance details> -- 找到了一個適合的slave來擔當新master
failover-state-send-slaveof-noone <instance details> -- 當把選擇爲新master的slave的身份進行切換的時候。
failover-end-
for
-timeout <instance details> -- failover因爲超時而失敗時。
failover-end <instance details> -- failover成功完成時。
switch-master <master name> <oldip> <oldport> <newip> <newport> -- 當master的地址發生變化時。一般這是客戶端最感興趣的消息了。
+tilt -- 進入Tilt模式。
-tilt -- 退出Tilt模式。
|
能夠看出,使用Sentinel命令和發佈訂閱兩種機制就能很好的實現和客戶端的集成整合:
使用get-master-addr-by-name和slaves指令能夠獲取當前的Master和Slaves的地址和信息;而當發生故障轉移時,即Master發生切換,能夠經過訂閱的+switch-master事件得到最新的Master信息。
sentinel.conf中的notification-script
在sentinel.conf中能夠配置多個sentinel notification-script <master name> <shell script-path>, 如sentinel notification-script mymaster ./check.sh
這個是在羣集failover時會觸發執行指定的腳本。腳本的執行結果若爲1,即稍後重試(最大重試次數爲10);若爲2,則執行結束。而且腳本最大執行時間爲60秒,超時會被終止執行。
目前會存在該腳本被執行屢次的問題,網上查找資料得到的解釋是:腳本分爲兩個級別, SENTINEL_LEADER 和 SENTINEL_OBSERVER ,前者僅由領頭 Sentinel 執行(一個 Sentinel),然後者由監視同一個 master 的全部 Sentinel 執行(多個 Sentinel)。
無failover時的配置糾正
即便當前沒有failover正在進行,sentinel依然會使用當前配置去設置監控的master。特別是:
1)根據最新配置確認爲slaves的節點卻聲稱本身是master(上文例子中被網絡隔離後的的redis3),這時它們會被從新配置爲當前master的slave。
2)若是slaves鏈接了一個錯誤的master,將會被改正過來,鏈接到正確的master。
Slave選舉與優先級
當一個sentinel準備好了要進行failover,而且收到了其餘sentinel的受權,那麼就須要選舉出一個合適的slave來作爲新的master。
slave的選舉主要會評估slave的如下幾個方面:
1)與master斷開鏈接的次數
2)Slave的優先級
3)數據複製的下標(用來評估slave當前擁有多少master的數據)
4)進程ID
若是一個slave與master失去聯繫超過10次,而且每次都超過了配置的最大失聯時間(down-after-milliseconds),若是sentinel在進行failover時發現slave失聯,那麼這個slave就會被sentinel認爲不適合用來作新master的。
更嚴格的定義是,若是一個slave持續斷開鏈接的時間超過
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
就會被認爲失去選舉資格。
符合上述條件的slave纔會被列入master候選人列表,並根據如下順序來進行排序:
1)sentinel首先會根據slaves的優先級來進行排序,優先級越小排名越靠前。
2)若是優先級相同,則查看複製的下標,哪一個從master接收的複製數據多,哪一個就靠前。
3)若是優先級和下標都相同,就選擇進程ID較小的那個。
一個redis不管是master仍是slave,都必須在配置中指定一個slave優先級。要注意到master也是有可能經過failover變成slave的。
若是一個redis的slave優先級配置爲0,那麼它將永遠不會被選爲master。可是它依然會從master哪裏複製數據。
故障轉移
所謂故障轉移就是當master宕機,選一個合適的slave來晉升爲master的操做,redis-sentinel會自動完成這個,不須要咱們手動來實現。
一次故障轉移操做大體分爲如下流程:
發現主服務器已經進入客觀下線狀態。
對咱們的當前集羣進行自增, 並嘗試在這個集羣中當選。
若是當選失敗, 那麼在設定的故障遷移超時時間的兩倍以後, 從新嘗試當選。 若是當選成功, 那麼執行如下步驟:
選出一個從服務器,並將它升級爲主服務器。
向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變爲主服務器。
經過發佈與訂閱功能, 將更新後的配置傳播給全部其餘 Sentinel , 其餘 Sentinel 對它們本身的配置進行更新。
向已下線主服務器的從服務器發送 SLAVEOF 命令, 讓它們去複製新的主服務器。
當全部從服務器都已經開始複製新的主服務器時, 領頭 Sentinel 終止此次故障遷移操做。
每當一個 Redis 實例被從新配置(reconfigured) —— 不管是被設置成主服務器、從服務器、又或者被設置成其餘主服務器的從服務器 —— Sentinel 都會向被從新配置的實例發送一個 CONFIG REWRITE 命令, 從而確保這些配置會持久化在硬盤裏。
Sentinel 使用如下規則來選擇新的主服務器:
在失效主服務器屬下的從服務器當中, 那些被標記爲主觀下線、已斷線、或者最後一次回覆 PING 命令的時間大於五秒鐘的從服務器都會被淘汰。
在失效主服務器屬下的從服務器當中, 那些與失效主服務器鏈接斷開的時長超過 down-after 選項指定的時長十倍的從服務器都會被淘汰。
在經歷了以上兩輪淘汰以後剩下來的從服務器中, 咱們選出複製偏移量(replication offset)最大的那個從服務器做爲新的主服務器; 若是複製偏移量不可用, 或者從服務器的複製偏移量相同, 那麼帶有最小運行 ID 的那個從服務器成爲新的主服務器。
Sentinel 自動故障遷移的一致性特質
Sentinel 自動故障遷移使用 Raft 算法來選舉領頭(leader) Sentinel , 從而確保在一個給定的紀元(epoch)裏, 只有一個領頭產生。
這表示在同一個紀元中, 不會有兩個 Sentinel 同時被選中爲領頭, 而且各個 Sentinel 在同一個紀元中只會對一個領頭進行投票。
更高的配置紀元老是優於較低的紀元, 所以每一個 Sentinel 都會主動使用更新的紀元來代替本身的配置。
簡單來講, 能夠將 Sentinel 配置看做是一個帶有版本號的狀態。 一個狀態會以最後寫入者勝出(last-write-wins)的方式(也便是,最新的配置老是勝出)傳播至全部其餘 Sentinel 。
舉個例子, 當出現網絡分割(network partitions)時, 一個 Sentinel 可能會包含了較舊的配置, 而當這個 Sentinel 接到其餘 Sentinel 發來的版本更新的配置時, Sentinel 就會對本身的配置進行更新。
若是要在網絡分割出現的狀況下仍然保持一致性, 那麼應該使用 min-slaves-to-write 選項, 讓主服務器在鏈接的從實例少於給定數量時中止執行寫操做, 與此同時, 應該在每一個運行 Redis 主服務器或從服務器的機器上運行 Redis Sentinel 進程。
Sentinel 狀態的持久化
Sentinel 的狀態會被持久化在 Sentinel 配置文件裏面。每當 Sentinel 接收到一個新的配置, 或者當領頭 Sentinel 爲主服務器建立一個新的配置時, 這個配置會與配置紀元一塊兒被保存到磁盤裏面。這意味着中止和重啓 Sentinel 進程都是安全的。
Sentinel 在非故障遷移的狀況下對實例進行從新配置
即便沒有自動故障遷移操做在進行, Sentinel 總會嘗試將當前的配置設置到被監視的實例上面。 特別是:
根據當前的配置, 若是一個從服務器被宣告爲主服務器, 那麼它會代替原有的主服務器, 成爲新的主服務器, 而且成爲原有主服務器的全部從服務器的複製對象。
那些鏈接了錯誤主服務器的從服務器會被從新配置, 使得這些從服務器會去複製正確的主服務器。
不過, 在以上這些條件知足以後, Sentinel 在對實例進行從新配置以前仍然會等待一段足夠長的時間, 確保能夠接收到其餘 Sentinel 發來的配置更新, 從而避免自身由於保存了過時的配置而對實例進行了沒必要要的從新配置。
總結來講,故障轉移分爲三個步驟:
1)從下線的主服務的全部從服務裏面挑選一個從服務,將其轉成主服務
sentinel狀態數據結構中保存了主服務的全部從服務信息,領頭sentinel按照以下的規則從從服務列表中挑選出新的主服務;
刪除列表中處於下線狀態的從服務;
刪除最近5秒沒有回覆過領頭sentinel info信息的從服務;
刪除與已下線的主服務斷開鏈接時間超過 down-after-milliseconds*10毫秒的從服務,這樣就能保留從的數據比較新(沒有過早的與主斷開鏈接);
領頭sentinel從剩下的從列表中選擇優先級高的,若是優先級同樣,選擇偏移量最大的(偏移量大說明覆制的數據比較新),若是偏移量同樣,選擇運行id最小的從服務。
2)已下線主服務的全部從服務改成複製新的主服務
挑選出新的主服務以後,領頭sentinel 向原主服務的從服務發送 slaveof 新主服務 的命令,複製新master。
3)將已下線的主服務設置成新的主服務的從服務,當其回覆正常時,複製新的主服務,變成新的主服務的從服務
同理,當已下線的服務從新上線時,sentinel會向其發送slaveof命令,讓其成爲新主的從。
舒適提示:還能夠向任意sentinel發生sentinel failover <masterName> 進行手動故障轉移,這樣就不須要通過上述主客觀和選舉的過程。
sentinel.conf文件配置參數解釋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
1)sentinel monitor mymaster 192.168.10.202 6379 2
Sentine監聽的maste地址,第一個參數是給master起的名字,第二個參數爲master IP,第三個爲master端口,第四個爲當該master掛了的時候,若想將該master判爲失效,
在Sentine集羣中必須至少2個Sentine贊成才行,只要該數量不達標,則就不會發生故障遷移。也就是說只要有2個sentinel認爲master下線,就認爲該master客觀下線,
啓動failover並選舉產生新的master。一般最後一個參數不能多於啓動的sentinel實例數。
這個配置是sentinel須要監控的master
/slaver
信息,格式爲sentinel monitor <mastername> <masterIP> <masterPort> <quorum>
其中<quorum>應該小於集羣中slave的個數,當失效的節點數超過了<quorum>,則認爲整個體系結構失效
不過要注意, 不管你設置要多少個 Sentinel 贊成才能判斷一個服務器失效, 一個 Sentinel 都須要得到系統中多數(majority) Sentinel 的支持, 才能發起一次自動故障遷移,
並預留一個給定的配置紀元 (configuration Epoch ,一個配置紀元就是一個新主服務器配置的版本號)。
換句話說, 在只有少數(minority) Sentinel 進程正常運做的狀況下, Sentinel 是不能執行自動故障遷移的。
-----------------------------------------------------------------------------------------------
2)sentinel down-after-milliseconds mymaster 30000
表示master被當前sentinel實例認定爲失效的間隔時間。
master在多長時間內一直沒有給Sentine返回有效信息,則認定該master主觀下線。也就是說若是多久沒聯繫上redis-servevr,認爲這個redis-server進入到失效(SDOWN)狀態。
若是服務器在給定的毫秒數以內, 沒有返回 Sentinel 發送的 PING 命令的回覆, 或者返回一個錯誤, 那麼 Sentinel 將這個服務器標記爲主觀下線(subjectively down,簡稱 SDOWN )。
不過只有一個 Sentinel 將服務器標記爲主觀下線並不必定會引發服務器的自動故障遷移: 只有在足夠數量的 Sentinel 都將一個服務器標記爲主觀下線以後, 服務器纔會被標記爲客觀下線
(objectively down, 簡稱 ODOWN ), 這時自動故障遷移纔會執行。
將服務器標記爲客觀下線所需的 Sentinel 數量由對主服務器的配置決定。
-----------------------------------------------------------------------------------------------
3)sentinel parallel-syncs mymaster 2
當在執行故障轉移時,設置幾個slave同時進行切換master,該值越大,則可能就有越多的slave在切換master時不可用,能夠將該值設置爲1,即一個一個來,這樣在某個
slave進行切換master同步數據時,其他的slave還能正常工做,以此保證每次只有一個從服務器處於不能處理命令請求的狀態。
parallel-syncs 選項指定了在執行故障轉移時, 最多能夠有多少個從服務器同時對新的主服務器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長。
若是從服務器被設置爲容許使用過時數據集(參見對 redis.conf 文件中對 slave-serve-stale-data 選項的說明), 那麼你可能不但願全部從服務器都在同一時間向新的主服務器發送同步請求,
由於儘管複製過程的絕大部分步驟都不會阻塞從服務器, 但從服務器在載入主服務器發來的 RDB 文件時, 仍然會形成從服務器在一段時間內不能處理命令請求: 若是所有從服務器一塊兒對新的主
服務器進行同步, 那麼就可能會形成全部從服務器在短期內所有不可用的狀況出現。
當新master產生時,同時進行
"slaveof"
到新master並進行
"SYNC"
的slave個數。
默認爲1,建議保持默認值
在salve執行salveof與同步時,將會終止客戶端請求。
此值較大,意味着
"集羣"
終止客戶端請求的時間總和和較大。
此值較小,意味着
"集羣"
在故障轉移期間,多個salve向客戶端提供服務時仍然使用舊數據。
-----------------------------------------------------------------------------------------------
4)sentinel can-failover mymaster
yes
在sentinel檢測到O_DOWN後,是否對這臺redis啓動failover機制
-----------------------------------------------------------------------------------------------
5)sentinel auth-pass mymaster 20180408
設置sentinel鏈接的master和slave的密碼,這個須要和redis.conf文件中設置的密碼同樣
-----------------------------------------------------------------------------------------------
6)sentinel failover-timeout mymaster 180000
failover過時時間,當failover開始後,在此時間內仍然沒有觸發任何failover操做,當前sentinel將會認爲這次failoer失敗。
執行故障遷移超時時間,即在指定時間內沒有大多數的sentinel 反饋master下線,該故障遷移計劃則失效
-----------------------------------------------------------------------------------------------
7)sentinel config-epoch mymaster 0
選項指定了在執行故障轉移時, 最多能夠有多少個從服務器同時對新的主服務器進行同步。這個數字越小, 完成故障轉移所需的時間就越長。
-----------------------------------------------------------------------------------------------
8)sentinel notification-script mymaster
/var/redis/notify
.sh
當failover時,能夠指定一個
"通知"
腳本用來告知當前集羣的狀況。
腳本被容許執行的最大時間爲60秒,若是超時,腳本將會被終止(KILL)
-----------------------------------------------------------------------------------------------
9)sentinel leader-epoch mymaster 0
同時一時間最多0個slave可同時更新配置,建議數字不要太大,以避免影響正常對外提供服務。
|
基於以上細節知識梳理,總結出sentinel的工做原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
首先要能理解SDOWN和ODOWN這兩個詞的含義,上面已經詳細介紹了它們倆。在此再提一下:
SDOWN:subjectively down,直接翻譯的爲
"主觀"
失效,即當前sentinel實例認爲某個redis服務爲
"不可用"
狀態.
ODOWN:objectively down,直接翻譯爲
"客觀"
失效,即多個sentinel實例都認爲master處於
"SDOWN"
狀態,那麼此時master將處於ODOWN,ODOWN能夠簡單理解爲master已經被集羣肯定
爲
"不可用"
,將會開啓failover.
SDOWN適合於master和slave,可是ODOWN只會使用於master;當slave失效超過
"down-after-milliseconds"
後,那麼全部sentinel實例都會將其標記爲
"SDOWN"
。
1) SDOWN與ODOWN轉換過程:
每一個sentinel實例在啓動後,都會和已知的slaves
/master
以及其餘sentinels創建TCP鏈接,並週期性發送PING(默認爲1秒)
在交互中,若是redis-server沒法在
"down-after-milliseconds"
時間內響應或者響應錯誤信息,都會被認爲此redis-server處於SDOWN狀態。
若是SDOWN的server爲master,那麼此時sentinel實例將會向其餘sentinel間歇性(一秒)發送
"is-master-down-by-addr <ip> <port>"
指令並獲取響應信息,若是足夠多的
sentinel實例檢測到master處於SDOWN,那麼此時當前sentinel實例標記master爲ODOWN...其餘sentinel實例作一樣的交互操做。
配置項
"sentinel monitor <mastername> <masterip> <masterport> <quorum>"
,若是檢測到master處於SDOWN狀態的slave個數達到<quorum>,那麼此時此sentinel實例將會認爲
master處於ODOWN。每一個sentinel實例將會間歇性(10秒)向master和slaves發送
"INFO"
指令,若是master失效且沒有新master選出時,每1秒發送一次
"INFO"
;
"INFO"
的主要目的就是
獲取並確認當前集羣環境中slaves和master的存活狀況。
通過上述過程後,全部的sentinel對master失效達成一致後,開始failover.
2) Sentinel與slaves
"自動發現"
機制:
在sentinel的配置文件中(
local
-sentinel.conf),都指定了port,此port就是sentinel實例偵聽其餘sentinel實例創建連接的端口.在集羣穩定後,最終會每一個sentinel實例之間都
會創建一個tcp連接,此連接中發送
"PING"
以及相似於
"is-master-down-by-addr"
指令集,可用用來檢測其餘sentinel實例的有效性以及
"ODOWN"
和
"failover"
過程當中信息的交互.
在sentinel之間創建鏈接以前,sentinel將會盡力和配置文件中指定的master創建鏈接.sentinel與master的鏈接中的通訊主要是基於pub
/sub
來發布和接收信息,發佈的信息內容包
括當前sentinel實例的偵聽端口:
+sentinel sentinel 127.0.0.1:26579 127.0.0.1 26579 ....
發佈的主題名稱爲
"__sentinel__:hello"
;同時sentinel實例也是
"訂閱"
此主題,以得到其餘sentinel實例的信息.因而可知,環境首次構建時,在默認master存活的狀況下,全部的
sentinel實例能夠經過pub
/sub
便可得到全部的sentinel信息,此後每一個sentinel實例便可以根據+sentinel信息中的
"ip+port"
和其餘sentinel逐個創建tcp鏈接便可.不過須要提醒
的是,每一個sentinel實例均會間歇性(5秒)向
"__sentinel__:hello"
主題中發佈本身的ip+port,目的就是讓後續加入集羣的sentinel實例也能或獲得本身的信息。
根據上文,咱們知道在master有效的狀況下,便可經過
"INFO"
指令得到當前master中已有的slave列表;此後任何slave加入集羣,master都會向
"主題中"
發佈
"+slave 127.0.0.1:6579 .."
,
那麼全部的sentinel也將當即得到slave信息,並和slave創建連接並經過PING檢測其存活性.
補充一下,每一個sentinel實例都會保存其餘sentinel實例的列表以及現存的master
/slaves
列表,各自的列表中不會有重複的信息(不可能出現多個tcp鏈接),對於sentinel將使用ip+port
作惟一性標記,
對於master
/slaver
將使用runid作惟一性標記,其中redis-server的runid在每次啓動時都不一樣.
3) Leader選舉:
其實在sentinels故障轉移中,仍然須要一個
"Leader"
來調度整個過程:master的選舉以及slave的重配置和同步。當集羣中有多個sentinel實例時,如何選舉其中一個sentinel爲leader呢?
在配置文件中
"can-failover"
"quorum"
參數,以及
"is-master-down-by-addr"
指令配合來完成整個過程。
A)
"can-failover"
用來代表當前sentinel是否能夠參與
"failover"
過程,若是爲
"YES"
則代表它將有能力參與
"Leader"
的選舉,不然它將做爲
"Observer"
,observer參與leader選舉投票但
不能被選舉;
B)
"quorum"
不只用來控制master ODOWN狀態確認,同時還用來選舉leader時最小
"贊同票"
數;
C)
"is-master-down-by-addr"
,它能夠用來檢測
"ip + port"
的master是否已經處於SDOWN狀態,不過此指令不只可以得到master是否處於SDOWN,同時它還額外的返回當前sentinel
本地
"投票選舉"
的Leader信息(runid);
每一個sentinel實例都持有其餘的sentinels信息,在Leader選舉過程當中(當爲leader的sentinel實例失效時,有可能master server並沒失效,注意分開理解),sentinel實例將從全部的
sentinels集合中去除
"can-failover = no"
和狀態爲SDOWN的sentinels,在剩餘的sentinels列表中按照runid按照
"字典"
順序排序後,取出runid最小的sentinel實例,並將它
"投票選舉"
爲Leader,並在其餘sentinel發送的
"is-master-down-by-addr"
指令時將推選的runid追加到響應中。每一個sentinel實例都會檢測
"is-master-down-by-addr"
的響應結果,若是
"投票選舉"
的
leader爲本身,且狀態正常的sentinels實例中,
"贊同者"
的本身的sentinel個數不小於(>=) 50% + 1,且不小與<quorum>,那麼此sentinel就會認爲選舉成功且leader爲本身。
在sentinel.conf文件中,咱們指望有足夠多的sentinel實例配置
"can-failover yes"
,這樣可以確保當leader失效時,可以選舉某個sentinel爲leader,以便進行failover。若是leader沒法產生,
好比較少的sentinels實例有效,那麼failover過程將沒法繼續.
4) failover過程:
在Leader觸發failover以前,首先wait數秒(隨即0~5),以便讓其餘sentinel實例準備和調整(有可能多個leader??),若是一切正常,那麼leader就須要開始將一個salve提高爲master,此slave
必須爲狀態良好(不能處於SDOWN
/ODOWN
狀態)且權重值最低(redis.conf中)的,當master身份被確認後,開始failover
A)
"+failover-triggered"
: Leader開始進行failover,此後緊跟着
"+failover-state-wait-start"
,wait數秒。
B)
"+failover-state-select-slave"
: Leader開始查找合適的slave
C)
"+selected-slave"
: 已經找到合適的slave
D)
"+failover-state-sen-slaveof-noone"
: Leader向slave發送
"slaveof no one"
指令,此時slave已經完成角色轉換,此slave即爲master
E)
"+failover-state-wait-promotition"
: 等待其餘sentinel確認slave
F)
"+promoted-slave"
:確認成功
G)
"+failover-state-reconf-slaves"
: 開始對slaves進行reconfig操做。
H)
"+slave-reconf-sent"
:向指定的slave發送
"slaveof"
指令,告知此slave跟隨新的master
I)
"+slave-reconf-inprog"
: 此slave正在執行slaveof + SYNC過程,如過slave收到
"+slave-reconf-sent"
以後將會執行slaveof操做。
J)
"+slave-reconf-done"
: 此slave同步完成,此後leader能夠繼續下一個slave的reconfig操做。循環G)
K)
"+failover-end"
: 故障轉移結束
L)
"+switch-master"
:故障轉移成功後,各個sentinel實例開始監控新的master。
|
2、redis sentinel 主從切換(failover)的容災環境部署記錄
redis主從複製簡單來講:
A)Redis的複製功能是支持多個數據庫之間的數據同步。一類是主數據庫(master)一類是從數據庫(slave),主數據庫能夠進行讀寫操做,當發生寫操做的時候自動將數據同步到從數據庫,而從數據庫通常是隻讀的,並接收主數據庫同步過來的數據,一個主數據庫能夠有多個從數據庫,而一個從數據庫只能有一個主數據庫。
B)經過redis的複製功能能夠很好的實現數據庫的讀寫分離,提升服務器的負載能力。主數據庫主要進行寫操做,而從數據庫負責讀操做。
Redis主從複製流程簡圖
redis主從複製的大體過程:
1)當一個從數據庫啓動時,會向主數據庫發送sync命令,
2)主數據庫接收到sync命令後會開始在後臺保存快照(執行rdb操做),並將保存期間接收到的命令緩存起來
3)當快照完成後,redis會將快照文件和全部緩存的命令發送給從數據庫。
4)從數據庫收到後,會載入快照文件並執行收到的緩存的命令。
注意:redis2.8以前的版本:當主從數據庫同步的時候從數據庫由於網絡緣由斷開重連後會從新執行上述操做,不支持斷點續傳。redis2.8以後支持斷點續傳。
0)Redis主從結構支持一主多從+n個sentinel模式,信息以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
192.168.10.202 redis-master redis(6379)、sentinel(26379)
192.168.10.203 redis-slave01 redis(6379)、sentinel(26379)
192.168.10.205 redis-slave02 redis(6379)、sentinel(26379)
關閉三個節點機器的iptables和selinux(全部節點機器上都要操做)
[root@redis-master ~]
# /etc/init.d/iptables stop
[root@redis-master ~]
# vim /etc/sysconfig/selinux
......
SELINUX=disabled
[root@redis-master ~]
# setenforce 0
[root@redis-master ~]
# getenforce
Permissive
注意:本案例採用1主2從+3 sentinel的集羣模式,全部從節點的配置都同樣。
|
a)redis服務器上各自存在一個Sentinel,監控本機redis的運行狀況,並通知給閉路環上其它的redis節點;
b)當master發生異常(例如:宕機和斷電等)致使不可運行時,Sentinel將通知給其它節點,而剩餘節點上的Sentinel將從新選舉出新的master,而原來的master從新恢復正常後,則一直扮演slave角色;
c)規定整個架構體系中,master提供讀寫服務,而slave只提供讀取服務。
1)redis一鍵安裝(三個節點上都要操做)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
[root@redis-master ~]
# cd /usr/local/src/
[root@redis-master src]
# vim install_redis.sh
#!/usr/bin/env bash
# It's Used to be install redis.
# Created on 2018/04/08 11:18.
# @author: wangshibo.
# Version: 1.0
function
install_redis () {
#################################################################################################
cd
/usr/local/src
if
[ ! -f
" redis-4.0.1.tar.gz"
];
then
wget http:
//download
.redis.io
/releases/redis-4
.0.1.
tar
.gz
fi
cd
/usr/local/src
tar
-zxvf
/usr/local/src/redis-4
.0.1.
tar
.gz
cd
redis-4.0.1
make
PREFIX=
/usr/local/redis
install
mkdir
-p
/usr/local/redis/
{etc,var}
rsync
-avz redis.conf
/usr/local/redis/etc/
sed
-i
's@pidfile.*@pidfile /var/run/redis-server.pid@'
/usr/local/redis/etc/redis
.conf
sed
-i
"s@logfile.*@logfile /usr/local/redis/var/redis.log@"
/usr/local/redis/etc/redis
.conf
sed
-i
"s@^dir.*@dir /usr/local/redis/var@"
/usr/local/redis/etc/redis
.conf
sed
-i
's/daemonize no/daemonize yes/g'
/usr/local/redis/etc/redis
.conf
sed
-i
's/^# bind 127.0.0.1/bind 0.0.0.0/g'
/usr/local/redis/etc/redis
.conf
#################################################################################################
}
install_redis
[root@redis-master src]
# chmod 755 install_redis.sh
[root@redis-master src]
# sh -x install_redis.sh
|
2)redis啓停腳本(三個節點上都要操做)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
[root@redis-master src]
# vim /etc/init.d/redis-server
#!/bin/bash
#
# redis - this script starts and stops the redis-server daemon
#
# chkconfig: - 85 15
# description: Redis is a persistent key-value database
# processname: redis-server
# config: /usr/local/redis/etc/redis.conf
# config: /etc/sysconfig/redis
# pidfile: /usr/local/redis/var/redis-server.pid
# Source function library.
.
/etc/rc
.d
/init
.d
/functions
# Source networking configuration.
.
/etc/sysconfig/network
# Check that networking is up.
[
"$NETWORKING"
=
"no"
] &&
exit
0
redis=
"/usr/local/redis/bin/redis-server"
prog=$(
basename
$redis)
REDIS_CONF_FILE=
"/usr/local/redis/etc/redis.conf"
[ -f
/etc/sysconfig/redis
] && .
/etc/sysconfig/redis
lockfile=
/var/lock/subsys/redis-server
start() {
[ -x $redis ] ||
exit
5
[ -f $REDIS_CONF_FILE ] ||
exit
6
echo
-n $
"Starting $prog: "
daemon $redis $REDIS_CONF_FILE
retval=$?
echo
[ $retval -
eq
0 ] &&
touch
$lockfile
return
$retval
}
stop() {
echo
-n $
"Stopping $prog: "
killproc $prog
retval=$?
echo
[ $retval -
eq
0 ] &&
rm
-f $lockfile
return
$retval
}
restart() {
stop
start
}
reload() {
echo
-n $
"Reloading $prog: "
killproc $redis -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >
/dev/null
2>&1
}
case
"$1"
in
start)
rh_status_q &&
exit
0
$1
;;
stop)
rh_status_q ||
exit
0
$1
;;
restart)
$1
;;
reload)
rh_status_q ||
exit
7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q ||
exit
0
;;
*)
echo
$
"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit
2
esac
執行權限
[root@redis-master src]
# chmod 755 /etc/init.d/redis-server
|
3)redis-sentinel啓停腳本示例(三個節點上都要操做)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
[root@redis-master src]
# vim /etc/init.d/redis-sentinel
#!/bin/bash
#
# redis-sentinel - this script starts and stops the redis-server sentinel daemon
#
# chkconfig: - 85 15
# description: Redis sentinel
# processname: redis-server
# config: /usr/local/redis/etc/sentinel.conf
# config: /etc/sysconfig/redis
# pidfile: /usr/local/redis/var/redis-sentinel.pid
# Source function library.
.
/etc/rc
.d
/init
.d
/functions
# Source networking configuration.
.
/etc/sysconfig/network
# Check that networking is up.
[
"$NETWORKING"
=
"no"
] &&
exit
0
redis=
"/usr/local/redis/bin/redis-sentinel"
prog=$(
basename
$redis)
REDIS_CONF_FILE=
"/usr/local/redis/etc/sentinel.conf"
[ -f
/etc/sysconfig/redis
] && .
/etc/sysconfig/redis
lockfile=
/var/lock/subsys/redis-sentinel
start() {
[ -x $redis ] ||
exit
5
[ -f $REDIS_CONF_FILE ] ||
exit
6
echo
-n $
"Starting $prog: "
daemon $redis $REDIS_CONF_FILE --sentinel
retval=$?
echo
[ $retval -
eq
0 ] &&
touch
$lockfile
return
$retval
}
stop() {
echo
-n $
"Stopping $prog: "
killproc $prog
retval=$?
echo
[ $retval -
eq
0 ] &&
rm
-f $lockfile
return
$retval
}
restart() {
stop
start
}
reload() {
echo
-n $
"Reloading $prog: "
killproc $redis -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >
/dev/null
2>&1
}
case
"$1"
in
start)
rh_status_q &&
exit
0
$1
;;
stop)
rh_status_q ||
exit
0
$1
;;
restart)
$1
;;
reload)
rh_status_q ||
exit
7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q ||
exit
0
;;
*)
echo
$
"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit
2
esac
執行權限:
[root@redis-master src]
# chmod 755 /etc/init.d/redis-sentinel
|
4)配置redis.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
a)編輯redis-master主節點的redis.conf文件
[root@redis-master src]
# mkdir -p /usr/local/redis/data/redis
[root@redis-master src]
# cp /usr/local/redis/etc/redis.conf /usr/local/redis/etc/redis.conf.bak
[root@redis-master src]
# vim /usr/local/redis/etc/redis.conf
bind 0.0.0.0
daemonize
yes
pidfile
"/usr/local/redis/var/redis-server.pid"
port 6379
tcp-backlog 128
timeout 0
tcp-keepalive 0
loglevel notice
logfile
"/usr/local/redis/var/redis-server.log"
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error
yes
rdbcompression
yes
rdbchecksum
yes
dbfilename dump.rdb
dir
"/usr/local/redis/data/redis"
#masterauth "20180408" #master設置密碼保護,即slave鏈接master時的密碼
#requirepass "20180408" #設置Redis鏈接密碼,若是配置了鏈接密碼,客戶端在鏈接Redis時須要經過AUTH <password>命令提供密碼,默認關閉
slave-serve-stale-data
yes
slave-
read
-only
yes
repl-diskless-
sync
no
repl-diskless-
sync
-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
appendonly
yes
#打開aof持久化
appendfilename
"appendonly.aof"
appendfsync everysec
# 每秒一次aof寫
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated
yes
lua-
time
-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events
""
hash
-max-ziplist-entries 512
hash
-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set
-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing
yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync
yes
注意:
上面配置中masterauth和requirepass表示設置密碼保護,若是設置了密碼,則鏈接redis後須要執行
"auth 20180408"
密碼後才能操做其餘命令。這裏我不設置密碼。
b)編輯redis-slave01和redis-slave02兩個從節點的redis.conf文件
[root@redis-slave01 src]
# mkdir -p /usr/local/redis/data/redis
[root@redis-slave01 src]
# cp /usr/local/redis/etc/redis.conf /usr/local/redis/etc/redis.conf.bak
[root@redis-slave01 src]
# vim /usr/local/redis/etc/redis.conf
bind 0.0.0.0
daemonize
yes
pidfile
"/usr/local/redis/var/redis-server.pid"
port 6379
tcp-backlog 128
timeout 0
tcp-keepalive 0
loglevel notice
logfile
"/usr/local/redis/var/redis-server.log"
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error
yes
rdbcompression
yes
rdbchecksum
yes
dbfilename dump.rdb
dir
"/usr/local/redis/data/redis"
#masterauth "20180408"
#requirepass "20180408"
slaveof 192.168.10.202 6379
#相對主redis配置,多添加了此行
slave-serve-stale-data
yes
slave-
read
-only
yes
#從節點只讀,不能寫入
repl-diskless-
sync
no
repl-diskless-
sync
-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
appendonly
yes
appendfilename
"appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated
yes
lua-
time
-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events
""
hash
-max-ziplist-entries 512
hash
-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set
-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing
yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync
yes
|
5)配置sentinel.conf(這個默認沒有,須要自建)。三個節點的配置同樣。
1
2
3
4
5
6
7
8
9
10
11
12
|
[root@redis-master src]
# mkdir -p /usr/local/redis/data/sentinel
[root@redis-master src]
# vim /usr/local/redis/etc/sentinel.conf
port 26379
pidfile
"/usr/local/redis/var/redis-sentinel.pid"
dir
"/usr/local/redis/data/sentinel"
daemonize
yes
protected-mode no
logfile
"/usr/local/redis/var/redis-sentinel.log"
sentinel monitor redisMaster 192.168.10.202 6379 2
sentinel down-after-milliseconds redisMaster 10000
sentinel parallel-syncs redisMaster 1
sentinel failover-timeout redisMaster 60000
|
6)啓動redis和sentinel(三個節點都要操做)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
設置系統變量
[root@redis-slave02 src]
# vim /etc/profile
.......
export
PATH=$PATH:
/usr/local/redis/bin
[root@redis-slave02 src]
# source /etc/profile
啓動redis和sentinel
[root@redis-master src]
# /etc/init.d/redis-server start
Starting redis-server: [ OK ]
[root@redis-master src]
# /etc/init.d/redis-sentinel start
Starting redis-sentinel: [ OK ]
[root@redis-master src]
# lsof -i:6379
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
redis-ser 2297 root 6u IPv4 7819726 0t0 TCP *:6379 (LISTEN)
redis-ser 2297 root 8u IPv4 7819778 0t0 TCP 192.168.10.202:6379->192.168.10.202:56226 (ESTABLISHED)
redis-ser 2297 root 9u IPv4 7819780 0t0 TCP 192.168.10.202:6379->192.168.10.202:56228 (ESTABLISHED)
redis-sen 2315 root 8u IPv4 7819777 0t0 TCP 192.168.10.202:56226->192.168.10.202:6379 (ESTABLISHED)
redis-sen 2315 root 9u IPv4 7819779 0t0 TCP 192.168.10.202:56228->192.168.10.202:6379 (ESTABLISHED)
[root@redis-master src]
# lsof -i:26379
COMMAND PID USER FD TYPE DEVICE SIZE
/OFF
NODE NAME
redis-sen 2315 root 6u IPv6 7819772 0t0 TCP *:26379 (LISTEN)
redis-sen 2315 root 7u IPv4 7819773 0t0 TCP *:26379 (LISTEN)
|
7)查看redis和sentinel信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
1)查看三個節點的redis的主從關係
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role
role:master
[root@redis-master src]
# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role
role:slave
[root@redis-master src]
# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role
role:slave
從上面信息能夠看出,192.168.10.202是master,192.168.10.203和192.168.10.205是slave
2)查看Master節點信息:
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379 info Replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.10.203,port=6379,state=online,offset=61480,lag=0
slave1:ip=192.168.10.205,port=6379,state=online,offset=61480,lag=0
master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:61626
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:61626
從上面信息看出,此時192.168.10.202的角色爲master,有兩個slave(203和205)被鏈接成功.
此時打開master的sentinel.conf,在末尾可看到以下自動寫入的內容:
[root@redis-master src]
# cat /usr/local/redis/etc/sentinel.conf
port 26379
pidfile
"/usr/local/redis/var/redis-sentinel.pid"
dir
"/usr/local/redis/data/sentinel"
daemonize
yes
protected-mode no
logfile
"/usr/local/redis/var/redis-sentinel.log"
sentinel myid c165761901b5ea3cd2d622bbf13f4c99eb73c1bc
sentinel monitor redisMaster 192.168.10.202 6379 2
sentinel down-after-milliseconds redisMaster 10000
sentinel failover-timeout redisMaster 60000
# Generated by CONFIG REWRITE
sentinel config-epoch redisMaster 0
sentinel leader-epoch redisMaster 0
sentinel known-slave redisMaster 192.168.10.203 6379
sentinel known-slave redisMaster 192.168.10.205 6379
sentinel known-sentinel redisMaster 192.168.10.205 26379 cc25d5f0e37803e888732d63deae3761c9f91e1d
sentinel known-sentinel redisMaster 192.168.10.203 26379 e1505ffc65f787871febfde2f27b762f70cddd71
sentinel current-epoch 0
[root@redis-master ~]
# redis-cli -h 192.168.10.205 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3
3)查看Slave節點信息:
先查看salve01節點信息
[root@redis-slave01 src]
# redis-cli -h 192.168.10.203 -p 6379 info Replication
# Replication
role:slave
master_host:192.168.10.202
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:96744
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:96744
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:96744
此時192.168.10.203的角色爲slave,它們所屬的master爲220。
此時打開slave的sentinel.conf,在末尾可看到以下自動寫入的內容:
[root@redis-slave01 src]
# cat /usr/local/redis/etc/sentinel.conf
port 26379
pidfile
"/usr/local/redis/var/redis-sentinel.pid"
dir
"/usr/local/redis/data/sentinel"
daemonize
yes
protected-mode no
logfile
"/usr/local/redis/var/redis-sentinel.log"
sentinel myid e1505ffc65f787871febfde2f27b762f70cddd71
sentinel monitor redisMaster 192.168.10.202 6379 2
sentinel down-after-milliseconds redisMaster 10000
sentinel failover-timeout redisMaster 60000
# Generated by CONFIG REWRITE
sentinel config-epoch redisMaster 0
sentinel leader-epoch redisMaster 0
sentinel known-slave redisMaster 192.168.10.203 6379
sentinel known-slave redisMaster 192.168.10.205 6379
sentinel known-sentinel redisMaster 192.168.10.205 26379 cc25d5f0e37803e888732d63deae3761c9f91e1d
sentinel known-sentinel redisMaster 192.168.10.202 26379 c165761901b5ea3cd2d622bbf13f4c99eb73c1bc
sentinel current-epoch 0
[root@redis-slave01 ~]
# redis-cli -h 192.168.10.203 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3
一樣查看slave02節點的信息
[root@redis-slave02 src]
# redis-cli -h 192.168.10.205 -p 6379 info Replication
# Replication
role:slave
master_host:192.168.10.202
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:99678
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:99678
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:170
repl_backlog_histlen:99509
[root@redis-slave02 src]
# cat /usr/local/redis/etc/sentinel.conf
port 26379
pidfile
"/usr/local/redis/var/redis-sentinel.pid"
dir
"/usr/local/redis/data/sentinel"
daemonize
yes
protected-mode no
logfile
"/usr/local/redis/var/redis-sentinel.log"
sentinel myid cc25d5f0e37803e888732d63deae3761c9f91e1d
sentinel monitor redisMaster 192.168.10.202 6379 2
sentinel down-after-milliseconds redisMaster 10000
sentinel failover-timeout redisMaster 60000
# Generated by CONFIG REWRITE
sentinel config-epoch redisMaster 0
sentinel leader-epoch redisMaster 0
sentinel known-slave redisMaster 192.168.10.205 6379
sentinel known-slave redisMaster 192.168.10.203 6379
sentinel known-sentinel redisMaster 192.168.10.203 26379 e1505ffc65f787871febfde2f27b762f70cddd71
sentinel known-sentinel redisMaster 192.168.10.202 26379 c165761901b5ea3cd2d622bbf13f4c99eb73c1bc
sentinel current-epoch 0
[root@redis-slave02 ~]
# redis-cli -h 192.168.10.205 -p 26379 info Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=redisMaster,status=ok,address=192.168.10.202:6379,slaves=2,sentinels=3
|
8)客戶端寫入測試數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
客戶端鏈接master節點,寫入一條數據
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379
192.168.10.202:6379>
set
name kevin;
OK
192.168.10.202:6379> get name;
"kevin"
;
而後客戶端再鏈接任意slave節點,經過get獲取上面的那條數據
[root@redis-master src]
# redis-cli -h 192.168.10.203 -p 6379
192.168.10.203:6379> get name
"kevin;"
192.168.10.203:6379>
set
name grace;
(error) READONLY You can't write against a
read
only slave.
192.168.10.203:6379>
[root@redis-master src]
# redis-cli -h 192.168.10.205 -p 6379
192.168.10.205:6379> get name
"kevin;"
192.168.10.205:6379>
set
name grace;
(error) READONLY You can't write against a
read
only slave.
192.168.10.205:6379>
由上面測試信息可知,master節點能夠寫入,能夠讀取;而slave節點默認只能讀取,不能寫入!這就實現了主從複製,讀寫分離了!
|
9)模擬故障(經過sentinel實現主從切換,sentinel也要部署多臺,即集羣模式,防止單臺sentinel掛掉狀況)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
1)關掉任意一個slave節點(好比關閉掉slave01節點),全部節點的sentinel均可以檢測到,出現以下示例信息:
[root@redis-master src]
# redis-cli -h 192.168.10.203 -p 6379
192.168.10.203:6379> get name
"kevin;"
192.168.10.203:6379>
set
name grace;
(error) READONLY You can't write against a
read
only slave.
192.168.10.203:6379>
shutdown
not connected>
說明:
shutdown
命令表示關閉redis
從上可看出203被sentinel檢測到已處於關閉狀態,此時再來查看剩餘節點的主從信息,它們的角色不會發生變化,只是master上的connected_slaves變爲了1。
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.10.205,port=6379,state=online,offset=219376,lag=1
master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:219376
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:219376
查看sentinel日誌(任意節點上查看),發現203節點已經進入
"+sdown"
狀態
[root@redis-master src]
# tail -f /usr/local/redis/var/redis-sentinel.log
2315:X 08 May 18:49:51.429 * Increased maximum number of
open
files to 10032 (it was originally
set
to 1024).
2315:X 08 May 18:49:51.431 * Running mode=sentinel, port=26379.
2315:X 08 May 18:49:51.431
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2315:X 08 May 18:49:51.463
# Sentinel ID is c165761901b5ea3cd2d622bbf13f4c99eb73c1bc
2315:X 08 May 18:49:51.463
# +monitor master redisMaster 192.168.10.202 6379 quorum 2
2315:X 08 May 18:50:11.544 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:11.574 * +slave slave 192.168.10.205:6379 192.168.10.205 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:15.088 * +sentinel sentinel e1505ffc65f787871febfde2f27b762f70cddd71 192.168.10.203 26379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:16.075 * +sentinel sentinel cc25d5f0e37803e888732d63deae3761c9f91e1d 192.168.10.205 26379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:06:07.669
# +sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
而後重啓上面被關閉的slave節點(即192.168.10.203),全部節點的sentinel均可以檢測到,可看出221又被sentinel檢測到已處於可用狀態,此時再來查看節點的主從信息,
它們的角色仍然不會發生變化,master上的connected_slaves又變爲了2
[root@redis-slave01 src]
# /etc/init.d/redis-server restart
Stopping redis-server: [FAILED]
Starting redis-server: [ OK ]
[root@redis-slave01 src]
# /etc/init.d/redis-server restart
Stopping redis-server: [ OK ]
Starting redis-server: [ OK ]
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.10.205,port=6379,state=online,offset=268216,lag=0
slave1:ip=192.168.10.203,port=6379,state=online,offset=268070,lag=1
master_replid:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:268216
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:268216
查看sentinel日誌(任意節點上查看),發現203節點已經進入
"-sdown"
狀態
[root@redis-master src]
# tail -f /usr/local/redis/var/redis-sentinel.log
2315:X 08 May 18:49:51.429 * Increased maximum number of
open
files to 10032 (it was originally
set
to 1024).
2315:X 08 May 18:49:51.431 * Running mode=sentinel, port=26379.
2315:X 08 May 18:49:51.431
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2315:X 08 May 18:49:51.463
# Sentinel ID is c165761901b5ea3cd2d622bbf13f4c99eb73c1bc
2315:X 08 May 18:49:51.463
# +monitor master redisMaster 192.168.10.202 6379 quorum 2
2315:X 08 May 18:50:11.544 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:11.574 * +slave slave 192.168.10.205:6379 192.168.10.205 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:15.088 * +sentinel sentinel e1505ffc65f787871febfde2f27b762f70cddd71 192.168.10.203 26379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 18:50:16.075 * +sentinel sentinel cc25d5f0e37803e888732d63deae3761c9f91e1d 192.168.10.205 26379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:06:07.669
# +sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:10:14.965 * +reboot slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:10:15.020
# -sdown slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
=======================================================================================================
2)關掉master節點(即192.168.10.202),待全部節點的sentinel都檢測到後(稍等一會,2-3秒鐘時間),再來查看兩個Slave節點的主從信息,發現其中一個節點的角色經過選舉後會成爲
master節點了!
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379
192.168.10.202:6379>
shutdown
not connected>
查看sentinel日誌(任意節點上查看),發現202節點已經進入
"+sdown"
狀態
[root@redis-master src]
# tail -f /usr/local/redis/var/redis-sentinel.log
2315:X 08 May 19:17:03.722
# +failover-state-reconf-slaves master redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:03.760 * +slave-reconf-sent slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:04.015 * +slave-reconf-inprog slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:04.459
# -odown master redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:05.047 * +slave-reconf-
done
slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:05.131
# +failover-end master redisMaster 192.168.10.202 6379
2315:X 08 May 19:17:05.131
# +switch-master redisMaster 192.168.10.202 6379 192.168.10.205 6379
2315:X 08 May 19:17:05.131 * +slave slave 192.168.10.203:6379 192.168.10.203 6379 @ redisMaster 192.168.10.205 6379
2315:X 08 May 19:17:05.131 * +slave slave 192.168.10.202:6379 192.168.10.202 6379 @ redisMaster 192.168.10.205 6379
2315:X 08 May 19:17:15.170
# +sdown slave 192.168.10.202:6379 192.168.10.202 6379 @ redisMaster 192.168.10.205 6379
[root@redis-slave01 src]
# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role
role:slave
[root@redis-slave01 src]
# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role
role:master
[root@redis-slave01 src]
# redis-cli -h 192.168.10.205 -p 6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.10.203,port=6379,state=online,offset=348860,lag=1
master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7
master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_repl_offset:349152
second_repl_offset:342824
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:170
repl_backlog_histlen:348983
[root@redis-slave01 src]
# redis-cli -h 192.168.10.203 -p 6379 info replication
# Replication
role:slave
master_host:192.168.10.205
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:347546
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7
master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_repl_offset:347546
second_repl_offset:342824
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:283207
repl_backlog_histlen:64340
由上可知,當master節點(即192.168.10.202)的redis關閉後,slave02節點(即192.168.10.205)變成了新的master節點,而slave01(即192.168.10.203)成爲
了slave02的從節點!
192.168.10.205節點此時被選舉爲master,此時打開的205節點的redis.conf文件,slaveof配置項已被自動刪除了。
而203從節點的redis.conf文件中slaveof配置項的值被自動修改成192.168.10.205 6379。
[root@redis-slave02 src]
# cat /usr/local/redis/etc/redis.conf|grep slaveof
[root@redis-slave01 src]
# cat /usr/local/redis/etc/redis.conf|grep slaveof
slaveof 192.168.10.205 6379
在這個新master上(即192.168.10.205)執行諸如
set
這樣的寫入操做將被成功執行
[root@redis-slave01 src]
# redis-cli -h 192.168.10.205 -p 6379
192.168.10.205:6379>
set
name beijing;
OK
[root@redis-master src]
# redis-cli -h 192.168.10.203 -p 6379
192.168.10.203:6379> get name
"beijing;"
192.168.10.203:6379>
set
name tianjin;
(error) READONLY You can't write against a
read
only slave.
192.168.10.203:6379>
重啓192.168.10.202節點的redis,待全部節點的sentinel都檢測到後,再來查看全部節點的主從信息,此時192.168.10.205節點的master角色不會被從新搶佔,
而192.168.10.202節點的角色會從原來的master變爲了slave。
[root@redis-master src]
# /etc/init.d/redis-server restart
Stopping redis-server: [FAILED]
Starting redis-server: [ OK ]
[root@redis-master src]
# /etc/init.d/redis-server restart
Stopping redis-server: [ OK ]
Starting redis-server: [ OK ]
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379 INFO|grep role
role:slave
[root@redis-master src]
# redis-cli -h 192.168.10.203 -p 6379 INFO|grep role
role:slave
[root@redis-master src]
# redis-cli -h 192.168.10.205 -p 6379 INFO|grep role
role:master
[root@redis-master src]
# redis-cli -h 192.168.10.205 -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.10.203,port=6379,state=online,offset=545410,lag=1
slave1:ip=192.168.10.202,port=6379,state=online,offset=545410,lag=1
master_replid:a51f87958cea0b1e8fe2c83542ca6cebace53bf7
master_replid2:96a1fd63d0ad9e7903851a82382e32d690667bcc
master_repl_offset:545556
second_repl_offset:342824
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:170
repl_backlog_histlen:545387
[root@redis-master src]
# redis-cli -h 192.168.10.202 -p 6379
192.168.10.202:6379> get name
"beijing;"
此時登陸192.168.10.202節點的redis,執行
"get name"
獲得的值爲beijing,而不是原來的kevin,由於192.168.10.202節點的redis重啓後會自動重新的master中同步
數據。此時打開192.168.10.202節點的redis.conf文件,會在末尾找到以下信息:
[root@redis-master src]
# cat /usr/local/redis/etc/redis.conf|grep slaveof
slaveof 192.168.10.205 6379
到此,已經驗證出了redis sentinel能夠自行實現主從的故障切換了!
|
10)客戶端如何鏈接redis sentinel?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
客戶端配置鏈接的是sentinel信息,好比鏈接sentinel.conf文件中定義的master名稱。在sentinel監聽時,當master節點掛了,它會在slave節點中自動選舉出新
的master節點,而當掛了的老master節點從新恢復後就會成爲新的slave節點。對於客戶端來講,redis主從切換後它不須要修改鏈接配置。
下面列出幾個客戶端鏈接redis sentinel的例子
1)java客戶端在jedis中使用redis sentinel哨兵方式鏈接
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<beans xmlns=
"http://www.springframework.org/schema/beans"
>
<bean
id
=
"jedisPoolConfig"
class=
"redis.clients.jedis.JedisPoolConfig"
>
<property name=
"maxTotal"
value=
"1000"
/>
<property name=
"maxIdle"
value=
"10"
/>
<property name=
"minIdle"
value=
"1"
/>
<property name=
"maxWaitMillis"
value=
"30000"
/>
<property name=
"testOnBorrow"
value=
"true"
/>
<property name=
"testOnReturn"
value=
"true"
/>
<property name=
"testWhileIdle"
value=
"true"
/>
<
/bean
>
<bean
id
=
"cacheService"
class=
"sentinel.CacheServiceImpl"
destroy-method=
"destroy"
>
<property name=
"jedisSentinlePool"
>
<bean class=
"redis.clients.jedis.JedisSentinelPool"
>
<constructor-arg index=
"0"
value=
"mymaster"
/>
<constructor-arg index=
"1"
>
<
set
>
<value>192.168.10.202:26379<
/value
>
<value>192.168.10.203:26379<
/value
>
<value>192.168.10.205:26379<
/value
>
<
/set
>
<
/constructor-arg
>
<constructor-arg index=
"2"
ref=
"jedisPoolConfig"
/>
<
/bean
>
<
/property
>
<
/bean
>
<
/beans
>
2)python鏈接redis sentinel集羣(須要安裝python redis客戶端,即執行
"pip install redis"
)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import
redis
from redis.sentinel
import
Sentinel
# 鏈接哨兵服務器(主機名也能夠用域名)
sentinel = Sentinel([(
'192.168.10.202'
, 26379),
(
'192.168.10.203'
, 26379),
(
'192.168.10.205'
, 26379)
],
socket_timeout=0.5)
# 獲取主服務器地址
master = sentinel.discover_master(
'mymaster'
)
print(master)
# 輸出:('192.168.10.202', 26379)
# 獲取從服務器地址
slave = sentinel.discover_slaves(
'mymaster'
)
print(slave)
# 輸出:[('192.168.10.203', 26379), ('192.168.10.205', 26379), ('172.31.0.5', 26379)]
# 獲取主服務器進行寫入
master = sentinel.master_for(
'mymaster'
, socket_timeout=0.5, password=
'redis_auth_pass'
, db=15)
w_ret = master.
set
(
'foo'
,
'bar'
)
# 輸出:True
# # 獲取從服務器進行讀取(默認是round-roubin)
slave = sentinel.slave_for(
'mymaster'
, socket_timeout=0.5, password=
'redis_auth_pass'
, db=15)
r_ret = slave.get(
'foo'
)
print(r_ret)
# # 輸出:bar
3)Java客戶端鏈接Redis(單sentinel).
下面例子中好的redisMaster和20180408是在sentinel.conf中定義的master名稱和鏈接密碼
package com.hiifit.cloudplatform.gaia.
test
;
import
java.util.HashSet;
import
java.util.Set;
import
redis.clients.jedis.Jedis;
import
redis.clients.jedis.JedisSentinelPool;
public class RedisSentinelTest {
@SuppressWarnings(
"deprecation"
)
public static void main(String[] args) {
Set<String> sentinels = new HashSet<String>();
String hostAndPort1 =
"192.168.10.205:26379"
;
sentinels.add(hostAndPort1);
String clusterName =
"redisMaster"
;
String password =
"20180408"
;
JedisSentinelPool redisSentinelJedisPool = new JedisSentinelPool(clusterName,sentinels,password);
Jedis jedis = null;
try {
jedis = redisSentinelJedisPool.getResource();
jedis.
set
(
"key"
,
"value"
);
} catch (Exception e) {
e.printStackTrace();
} finally {
redisSentinelJedisPool.returnBrokenResource(jedis);
}
redisSentinelJedisPool.close();
}
}
|