在Redis Sentinel環境下,jedis該如何配置


在Redis主從復制架構中,如果master出現了故障,則需要人工將slave提升為master,同時,通知應用側更新master的地址。這樣方式比較低效,對應用側影響較大。

 

為了解決這個問題,Redis 2.8中推出了自己的高可用方案Redis Sentinel。

 

Redis Sentinel架構圖如下:

 

默認情況下,每個Sentinel節點會以每秒一次的頻率對Redis節點和其它的Sentinel節點發送PING命令,並通過節點的回復來判斷節點是否在線。

如果在down-after-millisecondes毫秒內,沒有收到有效的回復,則會判定該節點為主觀下線。

如果該節點為master,則該Sentinel節點會通過sentinel is-master-down-by-addr命令向其它sentinel節點詢問對該節點的判斷,如果超過<quorum>個數的節點判定master不可達,則該sentinel節點會將master判斷為客觀下線。

這個時候,各個Sentinel會進行協商,選舉出一個領頭Sentinel,由該領頭Sentinel對master節點進行故障轉移操作。

故障轉移包含如下三個操作:

1. 在所有的slave服務器中,挑選出一個slave,並將其轉換為master。

2. 讓其它slave服務器,改為復制新的master。

3. 將舊master設置為新master的slave,這樣,當舊的master重新上線時,它會成為新master的slave。

 

以上的所有操作對業務都是透明的,當新的master上線后,Sentinel會自動將這個變化實時通知給業務方。

 

那么,業務側又該如何配置,才能撲捉到這個變化呢?

其實,這個主要取決於Redis客戶端工具是否支持Redis Sentinel,對於支持的客戶端工具來說,如Jedis,

只需將連接字符串設置為Sentinel地址即可。

 

下面,給出了一個測試代碼,並模擬了master發生故障,業務側是如何處理的?

 

代碼如下:

package com.victor_02;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;

public class JedisSentinelTest {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        Set<String> sentinels = new HashSet<String>();
        sentinels.add("192.168.244.10:26379");
        sentinels.add("192.168.244.10:26380");
        sentinels.add("192.168.244.10:26381");

        JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("mymaster", sentinels);
        Jedis jedis = null;
while (true) { Thread.sleep(1000); try { jedis = jedisSentinelPool.getResource(); Date now = new Date(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); String format_now = dateFormat.format(now); jedis.set("hello", "world"); String value = jedis.get("hello"); System.out.println(format_now + ' ' + value);
}
catch (Exception e) { System.out.println(e); } finally { if (jedis != null) try { jedis.close(); } catch (Exception e) { System.out.println(e); } } } } }

 

模擬故障:

# ./redis-cli -p 6380
127.0.0.1:6380> shutdown

 

上述代碼的輸出如下:

四月 16, 2017 10:39:44 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
四月 16, 2017 10:39:44 下午 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.244.10:6380, starting Sentinel listeners...
四月 16, 2017 10:39:44 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.244.10:6380
2017/04/16 22:39:45 world
2017/04/16 22:39:46 world
2017/04/16 22:39:47 world
2017/04/16 22:39:48 world
2017/04/16 22:39:49 world
2017/04/16 22:39:50 world
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Software caused connection abort: recv failed
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
四月 16, 2017 10:40:21 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.244.10:6381
四月 16, 2017 10:40:21 下午 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.244.10:6381
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool
2017/04/16 22:40:22 world
2017/04/16 22:40:23 world
2017/04/16 22:40:24 world
2017/04/16 22:40:25 world
2017/04/16 22:40:26 world

 

從上述輸出可以看出,在master發生故障前,業務側最后一次正常處理(22:39:50),到再次正常處理是(22:40:22),中間經過了32s。

而其中30s被用來判斷master節點是否主觀下線(由down-after-milliseconds來指定),整個切換的過程還是比較高效的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM