Redis應用學習——Redis Sentinal

1. Redis Sentinal解決主從複製的高可用問題

    1. 主從複製中存在的問題:java

  • 當主節點或從節點發生故障時,必須手動進行故障轉移
  • 單主節點,寫能力和存儲能力受限,由於只能在主節點進行寫操做,並且即使有多個從節點,但這些從節點存儲的數據也只是主節點的數據副本,實際上也就至關於數據只存儲在主節點一臺機器中。

    2. Redis Sentinal主要就是解決了主從複製中的手動故障轉移所帶來的麻煩,從而實現了自動故障轉移,主從複製中的故障轉移問題詳見上一篇博客Redis應用學習(六)——主從複製,Redis Sentinal就是負責監控全部的主從節點、實現自動故障轉移流程而且通知客戶端故障遷移(客戶端故障遷移指客戶端所鏈接的Redis發生了故障,客戶端的鏈接會遷移到另外一個正常的Redis上),但注意,sentinel只能對主節點進行故障轉移和通知客戶端遷移鏈接,對於從節點,sentinel沒法進行故障轉移,也沒法通知客戶端進行鏈接遷移,只能對其作一個下線操做。linux

2. 認識Redis Sentinal

    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

  • 多個Sentinal節點投票肯定Redis主節點發生故障
  • Sentinal節點間投票選出一個Sentinal節點做爲領導者
  • 經過選舉出來的Sentinal領導者節點來Redis從節點中選出一個做爲新的Redis主節點
  • Sentinal領導者節點將其他的Redis從節點遷移到新的Redis主節點下
  • 通知客戶端主從節點變化,將鏈接原主節點的客戶端鏈接到新主節點上
  • 若是發生故障的原主節點又恢復正常,那麼就將恢復正常的節點變爲新主節點的從節點

    4. 一個Redis Sentinal能夠監控多套主從節點,詳細實現下面會進行說明。架構

3. Redis Sentinal的安裝與配置

    1. 安裝過程:運維

  • 首先須要安裝配置一套Redis主從節點,不作詳細過程
  • Sentinal節點配置:在Redis解壓後的安裝包文件夾中,有一個Sentinal基礎配置文件sentinel.conf,就是該文件對Sentinal進行配置,主要修改如下部分參數
    • port 26379:上面說過,Sentinal其實是一個特殊的Redis,因此須要配置運行時佔用端口
    • dir "":日誌文件存放目錄
    • logfile "port.log":生成的日誌文件名
    • sentinal monitor master-name  master-ip master-port count:配置監控的Redis主節點,master-name表示要給監控的Redis主節點起一個名,必需要惟一,master-ip和master-port就是主節點的IP地址和端口,最後的count參數就是表示當count個sentinel節點都肯定該主節點發生故障時,就會進行故障轉移
    • sentinel down-after-milliseconds master-name 30000:master-name就某個被監控的主節點,30000這個數字就表示若是該主節點若是超過30000毫秒一直都沒法ping通,那麼就就會被當前sentinel節點斷定爲故障
    • sentinel parallel-syncs master-name count:當主節點master-name被肯定爲故障時,就會發生故障轉移,此時某個從節點就會被sentinel設置爲新的主節點,其餘從節點就會從新和該新主節點創建主從關係,而且每一個從節點都會和新主節點執行一次全量複製,然後面的參數count就表示是同時只容許count個從節點進行全量複製dom

    • sentinel failover-timeout  master-name number:進行故障轉移的時間性能

    • daemonize yes:表示進行啓動sentinel節點以守護線程方式啓動學習

       

  • 啓動sentinel:經過redis-sentinel和配置文件啓動,好比 ./redis-sentinel sentinel-26380.conf
  • 經過客戶端鏈接sentinel節點,注意,sentinel節點沒法執行Redis中的任何數據讀寫命令,只有極少命令,好比info命令就是用來獲取sentinel節點自身全部的相關信息,經過這些信息能夠得到sentinel是否配置啓動成功

4. Redis Sentinal的Java客戶端

    1. Sentinal的服務端與客戶端的高可用:若是Sentinal不能實現主節點自動故障轉移後通知客戶端,那麼Sentinal功能就僅僅只是實現了服務端的高可用,好比發生故障遷移後新的Redis節點IP地址和端口號不發送給客戶端,那麼Sentinal所實現的自動故障轉移對於客戶端來講至關於無效的,因此Sentinal還會在自動故障轉移以後,通知客戶端Redis主節點的變化,並返回信息,使得客戶端也得以作出相應的改變從新鏈接到新的Redis主節點,那麼就能夠實現客戶端的高可用。

    2. 經過Redis Sentinal實現客戶端高可用的原理:

  • 首先遍歷一邊Sentinal節點集合,獲取一個可用的Sentinal節點
  • 進入sentinel客戶端,經過命令sentinel get-master-addr-by-name mymaster 便可獲取可用Redis主節點的IP地址和端口號
  • 在獲取到Redis主節點信息時,還會自動向主節點執行一條role或role replication命令來進行驗證,驗證IP地址和端口號是不是真的主節點
  • 若是Redis主節點中發生了故障轉移,監視主從節點的變化的sentinel就會把這些變化通知給客戶端

    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();
				}
			}
		}
	}

5. Redis Sentinal的服務端高可用原理

    1. 三個定時任務:三個定時任務實現了自動故障轉移中最重要的故障檢測,經過如下三個定時任務就能發現出現故障的各個節點

  • 每一個sentinel節點每10秒都會向本身監控的每一套Redis主從節點發送一條info命令來獲取節點信息,以此來發現從節點並確認主從關係
  • 每2秒每一個sentinel節點都會經過本身監控的主節點的channel(利用Redis的發佈訂閱功能實現)來交換信息,經過主節點中的_sentinel_:hello頻道來實現各個sentinel間的交互,交互各個sentinel對主從節點甚至是其餘sentinel節點的"見解"和自身信息
  • 每一秒每一個sentinel節點都會對其餘sentinel節點和Redis節點作ping命令操做

    2. 主觀下線和客觀下線:兩個相關配置參數

  • sentinal monitor master-name  master-ip master-port count:sentinel的配置文件中該配置參數就是用來讓sentinel節點監控一個Redis主節點及其從節點,並且經過count參數(若是超過count個sentinel節點都主觀肯定該Redis節點處於下線狀態,那麼該Redis節點就是處於客觀下線)來進行判斷是否該Redis節點是客觀下線
  • sentinel down-after-milliseconds master-name 30000:該配置文件用於sentinel節點對Redis主節點及其從節點判斷是否主觀下線,若是某個sentinel節點對Redis節點超過30000毫秒一直處於沒法ping通的狀況,那麼該節點就會被當前sentinel節點判斷爲主觀下線

     3. 領導者選舉:上面說過,在進行自動故障轉移以前,sentinel節點羣必需要選出一個sentinel節點做爲領導者,領導者來執行故障轉移操做

  • 當一個Redis節點確認下線後,每一個監控該節點並對其作了主觀下線的sentinel節點都會給其餘每個sentinel節點發送一個命令(sentinel is-master-down-by-addr)都但願本身成爲領導者
  • 收到領導者請求命令的sentinel節點若是在此以前沒有收到其餘sentinel節點的請求命令,那麼該請求命令就會被贊成,不然被拒絕
  • 若是sentinel節點發現贊成本身做爲領導者的票數過半且超過count個,那麼就會成爲領導者執行故障轉移
  • 若是有多個sentinel節點成爲了領導者或沒有sentinel節點成爲領導者,那麼將會從新選舉

    4. 故障轉移中的從節點選擇:在故障轉移中,若是主節點確認下線,那麼則須要選擇一個從節點來做爲新的主節點,選擇規則有

  • 選擇從節點的salve-priority(節點優先級,能夠在配置文件中進行配置,但通常不會修改)最高的節點,若是有則返回,不然執行下一條規則
  • 選擇複製偏移量最大的從節點(意味着它的數據複製的完整度是最接近原來的主節點的),若是存在則返回該節點,不然執行下一條規則
  • 選擇從節點中run-id最小的,這意味着該節點是運行時間最久的(或者說啓動最先的)。

6. Redis Sentinal的常見運維

    1. 節點運維:就是節點的手動上線和下線操做,針對的目標是Redis主節點、從節點和sentinel節點。

    2. 節點運維解決的問題:當下面這些問題發生時,應該由手動執行節點的上下線操做來進行一個故障轉移

  • 機器下線:因爲某種緣由致使機器不能在使用(好比機器使用時間超過保質期等)
  • 機器性能不足:例如CPU、內存、硬盤等
  • 節點自身運行故障:例如系統宕機等

    3. 對於主節點的下線:手動指定一個sentinel節點做爲領導者,並對指定的Redis主節點進行故障轉移:sentinel failover master-name,在某個sentinel節點的客戶端運行該命令就是指定該sentinel節點爲領導者,而且對其所監控的master-name節點進行故障轉移

    4. 對於從節點的下線:首先須要肯定是臨時下線(暫時關閉該節點,以後還會進行重啓)仍是永久下線(再也不使用這臺機器做爲一個從節點提供服務),下線後是否須要進行一些清理工做,好比從節點的一些配置,AOF、RDB以及日誌文件的清理,好比若是要臨時下線來啓動一下其餘進程,要保證從節點的相關配置不會干擾到新進程的運行。此外,從節點的下線還要考慮讀寫分離的問題。

    5. 對於sentinel節點的下線:與從節點相似

    6. 節點上線:對於Redis主節點的上線,一樣使用sentinel failover命令切換主節點便可;而對於從節點的上線使用slaveof命令將該從節點關聯到主節點便可,sentinel會自動感知;對於sentinel節點的上線,只須要寫好配置文件直接啓動便可。

7. Redis Sentinal中高可用讀寫分離的實現

    1. Redis Sentinal中讀寫分離存在的問題:客戶端鏈接到一個從節點只進行讀操做,但若是該從節點下線後,客戶端沒法獲知下線信息,也沒法將鏈接轉移到另外一個從節點上,由於sentinel只對從節點進行一個主觀下線操做,但不會通知客戶端從節點的下線信息,也就沒法作客戶端鏈接遷移(將鏈接原從節點的客戶端轉移到另外一個從節點上)。

    2. 要實現高可用的讀寫分離,客戶端就要知道從節點變化的三個消息:

  • 切換爲主節點,也就是從節點晉升爲主節點
  • 切換爲從節點,主節點變爲從節點
  • 從節點下線

    3. 實現原理:鏈接從節點的客戶端必須能感知到全部從節點的變化,也就是上面的三條消息,可是Java客戶端裏並無提供這種從節點的讀寫分離實現,須要咱們本身去實現,能夠參考JedisSentinelPool的實現來手動編寫一個從節點高可用鏈接池。但很明顯,sentinel環境下實現讀寫分離的高可用很是複雜,對於性能提升、容量擴展的時候,這種方式是比較複雜的,因此,推薦使用集羣(redis-cluster)。

相關文章
相關標籤/搜索