1. 程式人生 > >關於 Redis Cluster 模式下獲取 Java Client 的問題

關於 Redis Cluster 模式下獲取 Java Client 的問題

Redis連線池對於單機模式來說,官網有提供個JedisPool工具類,用起來也比較方便
但是對於Redis叢集模式下,官網沒有提供連線池的工具類,於是就需要我們自己來實現類似的功能了,我這裡採用的是單例模式的方法來解決高併發的場景。

單機模式

如果對於 Redis 是單機模式下的話,那麼 Redis 有提供一個JedisPool類 用來構建 Redis Client 的連線池,非常方便,簡單程式碼如下:

JedisPoolConfig config = new JedisPoolConfig();
//控制一個pool最多有多少個狀態為idle(空閒的)的jedis例項。
config.setMaxIdle(5); //控制一個pool可分配多少個jedis例項,通過pool.getResource()來獲取;如果賦值為-1,則表示不限制;如果pool已經分配了maxActive個jedis例項,則此時pool的狀態為exhausted(耗盡)。在borrow一個jedis例項時,是否提前進行validate操作;如果為true,則得到的jedis例項均是可用的; config.setMaxTotal(1000 * 100); //表示當borrow(引入)一個jedis例項時,最大的等待時間,如果超過等待時間,則直接丟擲JedisConnectionException; config.setMaxWaitMillis(30
); config.setTestOnBorrow(true); config.setTestOnReturn(true); //如果你遇到 java.net.SocketTimeoutException: Read timed out exception的異常資訊,請嘗試在構造JedisPool的時候設定自己的超時值. JedisPool預設的超時時間是2秒(單位毫秒) pool = new JedisPool(config, "127.0.0.1", 6379); /* * 獲得jedis連線 */ Jedis jedis = pool.getResource();

叢集模式

單機模式Redis官方有提供JedisPool類,用起來非常方便。
但是,如果Redis部署的是叢集模式,你會發現,官方根本就沒有提供叢集模式下的連線池的類!!
官方有提供一個JedisClsuter

的客戶端類。但是如果在高併發的情況下,每要處理一次就新建一個JedisCluster,那麼顯然這種方式是不可取的!

那麼問題來了,Redis叢集模式應該如何解決高併發的場景呢?

咦,這是我想到了一個自己感覺很不錯的方法,就是採用單例模式,簡單的程式碼如下:

public class JedisClsuterUtil {
    private static JedisCluster jedis = null;

    private JedisClsuterUtil(){}

    public static JedisCluster getJedis(){
        if(jedis==null){
            synchronized(JedisClsuterUtil.class){
                if(jedis==null){
                    Set<HostAndPort> hostAndPortSet = new HashSet();
                    hostAndPortSet.add(new HostAndPort("host1", 9001));
                    hostAndPortSet.add(new HostAndPort("host2", 9002));
                    // ....

                    jedis = new JedisCluster(hostAndPortSet);
                }
            }
        }
        return jedis;
    }
}

用該方法測試過,是沒有問題的。

改進:
上面是依靠double-checked locking的,這是一種不正確的用法,並不能達到預期目標。
所以以下是單例模式的改進版:

public class JedisClsuterUtil {

    private JedisClsuterUtil(){}

    public static JedisCluster getJedis(){
        return JedisClusterHolder.jedis;    
    }

    private static class JedisClusterHolder{
        private static Set<HostAndPort> hostAndPortSet;
        static {
            hostAndPortSet = new HashSet();
            hostAndPortSet.add(new HostAndPort("host1", 9001));
            hostAndPortSet.add(new HostAndPort("host2", 9002));
        }
        private static JedisCluster jedis = new JedisCluster(hostAndPortSet);
    }
}

各位有什麼更好的想法或者問題可以提出來討論討論。。