1. 主從複製中存在的問題:java
2. Redis Sentinal主要就是解決了主從複製中的手動故障轉移所帶來的麻煩,從而實現了自動故障轉移,主從複製中的故障轉移問題詳見上一篇博客Redis應用學習(六)——主從複製,Redis Sentinal就是負責監控全部的主從節點、實現自動故障轉移流程而且通知客戶端故障遷移(客戶端故障遷移指客戶端所鏈接的Redis發生了故障,客戶端的鏈接會遷移到另外一個正常的Redis上),但注意,sentinel只能對主節點進行故障轉移和通知客戶端遷移鏈接,對於從節點,sentinel沒法進行故障轉移,也沒法通知客戶端進行鏈接遷移,只能對其作一個下線操做。linux
1. Redis Sentinal架構:多個Sentinal節點構成一個Redis Sentinal,每一個Sentinal節點都會監控着Redis中的每個主從節點,多個Sentinal節點組成Redis Sentinal功能提供了Redis Sentinal功能的高可用型,好比當某個Sentinal節點判斷Redis主節點爲故障時,其餘Sentinal節點也會測試該Redis主節點是否故障,進行一個相似於投票的過程,若是投票結果肯定該Redis主節點確實故障,那麼就會進行故障轉移,並且即使某個Sentinal節點發生故障,其餘的Sentinal節點也能保持Redis Sentinal功能的正常運行。而對於客戶端來講,其不須要記錄(直連)某個Redis節點的信息(IP地址和端口等)來進行讀寫,而是記錄Redis Sentinal的信息(IP地址和端口等)進行交互redis
2. Sentinal節點:每一個Sentinal節點實際上就至關於一個特殊的Redis,可是不能存儲數據,默認佔用端口26379,能夠經過一個配置文件來修改啓動的相關配置apache
3. Sentinal對於主節點故障的處理:大體原理過程和手動過程相似,可是是由Sentinal自動完成的,從節點故障不會進行故障轉移和通知客戶端進行鏈接遷移centos
4. 一個Redis Sentinal能夠監控多套主從節點,詳細實現下面會進行說明。架構
1. 安裝過程:運維
sentinel parallel-syncs master-name count:當主節點master-name被肯定爲故障時,就會發生故障轉移,此時某個從節點就會被sentinel設置爲新的主節點,其餘從節點就會從新和該新主節點創建主從關係,而且每一個從節點都會和新主節點執行一次全量複製,然後面的參數count就表示是同時只容許count個從節點進行全量複製dom
sentinel failover-timeout master-name number:進行故障轉移的時間性能
daemonize yes:表示進行啓動sentinel節點以守護線程方式啓動學習
1. Sentinal的服務端與客戶端的高可用:若是Sentinal不能實現主節點自動故障轉移後通知客戶端,那麼Sentinal功能就僅僅只是實現了服務端的高可用,好比發生故障遷移後新的Redis節點IP地址和端口號不發送給客戶端,那麼Sentinal所實現的自動故障轉移對於客戶端來講至關於無效的,因此Sentinal還會在自動故障轉移以後,通知客戶端Redis主節點的變化,並返回信息,使得客戶端也得以作出相應的改變從新鏈接到新的Redis主節點,那麼就能夠實現客戶端的高可用。
2. 經過Redis Sentinal實現客戶端高可用的原理:
3. Java客戶端jedis實現對Redis Sentinal監控下的Redis主節點的鏈接以及發送命令:jedis客戶端的實現原理基本與上面所寫吻合,示例代碼
import java.util.LinkedHashSet; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisSentinelPool; /** * @ClassName:TestJedisSentinelPool * @Description:鏈接由Redis Sentinel監視的Redis主節點 */ public class TestJedisSentinelPool { //注意,Dubug測試該方法時要保證linux系統的防火牆關閉(centos7關閉指令爲systemctl stop firewalld) public static void main(String[] args) { /* * 建立一個jedis鏈接池,不過該鏈接池建立的jedis對象所鏈接的Redis是被Sentinel監控的主節點 * masterName表示Sentinel配置中的Redis主節點名 * sentinels表示全部的Sentinel節點的IP地址與端口號信息 * poolConfig表示該鏈接池的相關配置參數 */ String masterName="mymaster"; Set<String> sentinels=new LinkedHashSet<String>(); sentinels.add("192.168.10.128:26380"); sentinels.add("192.168.10.128:26381"); sentinels.add("192.168.10.128:26382"); GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig(); JedisSentinelPool pool=new JedisSentinelPool(masterName, sentinels, poolConfig); Jedis jedis=null; try { //注意,這裏返回的jedis對象鏈接的仍然是Redis節點,並非sentinel節點 jedis=pool.getResource(); //經過jedis就能夠執行Redis的相關命令 String response=jedis.set("user", "lisi"); System.out.println(response); } catch (Exception e) { // 異常處理 }finally { if(jedis!=null){ //回收jedis鏈接對象 jedis.close(); } } } }
Debug測試結果截圖:
4. 模擬故障轉移,觀察jedis客戶端的變化:要觀察這種變化,須要模擬真正應用環境中,jedis客戶端會不停的執行一些操做,因此更改上面的示例代碼,添加一個while死循環來生成隨機數,而後運行客戶端測試程序,而後關閉linux系統中的Redis主節點,就能夠觀察到jedis中的變化,觀察到服務端故障轉移的過程,一旦鏈接的Redis主節點故障,客戶端就會一直報錯,可是報錯一段時間以後又會中止報錯繼續成功執行,這個變化就是服務端自動故障轉移的表現。
//測試觀察服務端自動故障轉移在客戶端的表現 public void test(){ String masterName="mymaster"; Set<String> sentinels=new LinkedHashSet<String>(); sentinels.add("192.168.10.128:26380"); sentinels.add("192.168.10.128:26381"); sentinels.add("192.168.10.128:26382"); GenericObjectPoolConfig poolConfig=new GenericObjectPoolConfig(); JedisSentinelPool pool=new JedisSentinelPool(masterName, sentinels, poolConfig); Jedis jedis=null; Random rand=new Random(); String key=null; int value=0; int count=0; while(true){ count++; try { value=rand.nextInt(10000); key="key-"+value; jedis=pool.getResource(); String response=jedis.set(key, value+""); //每隔1秒輸出一次成功執行的結果 if(count%100==0){ System.out.println("set "+key+":"+value+" "+response); } TimeUnit.MILLISECONDS.sleep(10);//每10毫秒執行一次循環 } catch (Exception e) { // 錯誤提示 System.out.println("set "+key+":"+value+" failed"); //sentinel斷定Redis主節點是否爲故障,若是肯定主節點故障,則進行自動故障轉移 System.out.println("服務端Redis節點異常,判斷是否進行自動故障轉移"); }finally { if(jedis!=null){ //回收jedis鏈接對象 jedis.close(); } } } }
1. 三個定時任務:三個定時任務實現了自動故障轉移中最重要的故障檢測,經過如下三個定時任務就能發現出現故障的各個節點
2. 主觀下線和客觀下線:兩個相關配置參數
3. 領導者選舉:上面說過,在進行自動故障轉移以前,sentinel節點羣必需要選出一個sentinel節點做爲領導者,領導者來執行故障轉移操做
4. 故障轉移中的從節點選擇:在故障轉移中,若是主節點確認下線,那麼則須要選擇一個從節點來做爲新的主節點,選擇規則有
1. 節點運維:就是節點的手動上線和下線操做,針對的目標是Redis主節點、從節點和sentinel節點。
2. 節點運維解決的問題:當下面這些問題發生時,應該由手動執行節點的上下線操做來進行一個故障轉移
3. 對於主節點的下線:手動指定一個sentinel節點做爲領導者,並對指定的Redis主節點進行故障轉移:sentinel failover master-name,在某個sentinel節點的客戶端運行該命令就是指定該sentinel節點爲領導者,而且對其所監控的master-name節點進行故障轉移
4. 對於從節點的下線:首先須要肯定是臨時下線(暫時關閉該節點,以後還會進行重啓)仍是永久下線(再也不使用這臺機器做爲一個從節點提供服務),下線後是否須要進行一些清理工做,好比從節點的一些配置,AOF、RDB以及日誌文件的清理,好比若是要臨時下線來啓動一下其餘進程,要保證從節點的相關配置不會干擾到新進程的運行。此外,從節點的下線還要考慮讀寫分離的問題。
5. 對於sentinel節點的下線:與從節點相似
6. 節點上線:對於Redis主節點的上線,一樣使用sentinel failover命令切換主節點便可;而對於從節點的上線使用slaveof命令將該從節點關聯到主節點便可,sentinel會自動感知;對於sentinel節點的上線,只須要寫好配置文件直接啓動便可。
1. Redis Sentinal中讀寫分離存在的問題:客戶端鏈接到一個從節點只進行讀操做,但若是該從節點下線後,客戶端沒法獲知下線信息,也沒法將鏈接轉移到另外一個從節點上,由於sentinel只對從節點進行一個主觀下線操做,但不會通知客戶端從節點的下線信息,也就沒法作客戶端鏈接遷移(將鏈接原從節點的客戶端轉移到另外一個從節點上)。
2. 要實現高可用的讀寫分離,客戶端就要知道從節點變化的三個消息:
3. 實現原理:鏈接從節點的客戶端必須能感知到全部從節點的變化,也就是上面的三條消息,可是Java客戶端裏並無提供這種從節點的讀寫分離實現,須要咱們本身去實現,能夠參考JedisSentinelPool的實現來手動編寫一個從節點高可用鏈接池。但很明顯,sentinel環境下實現讀寫分離的高可用很是複雜,對於性能提升、容量擴展的時候,這種方式是比較複雜的,因此,推薦使用集羣(redis-cluster)。