redis實戰第十五篇 redis cluster的批處理中ask重定向解決方案

ask重定向現象請參考【傳送門

分別使用mget和pipline做批處理
1.使用mget批量獲取,如果存在重定向問題,會拋出異常。

    @Test
    public void testMget(){
        JedisCluster jedis = RedisClusterUtil.getJedis();
        List<String> results = null;
        results = jedis.mget("user:{info}:id","user:{info}:age");
        for(String res:results){
            System.out.println(res);
        }
        results = jedis.mget("user:{info}:id","user:{info}:age","user:{info}:name","user:{info}:email");
        for(String res:results){
            System.out.println(res);
        }
    }

返回結果如下所示,第一次mget執行成功,是因爲兩個鍵都遷移完成,第二次獲取失敗是因爲存在ask重定向問題。

232132
20

redis.clients.jedis.exceptions.JedisDataException: TRYAGAIN Multiple keys request during rehashing of slot

2.使用pipline做批量處理

@Test
    public void testPiplione(){
        //創建JedisCluster時,節點地址可以只填寫部分,集羣內部可以通過cluster nodes獲取所有節點信息
        JedisSlotBasedConnectionHandler connectionHandler = new JedisCluster(new HostAndPort("192.168.0.31",6380),1000,1000,5,"1234@abcd",new JedisPoolConfig()){
            public JedisSlotBasedConnectionHandler getConnectionHandler() {
                return (JedisSlotBasedConnectionHandler) super.connectionHandler;
            }
        }.getConnectionHandler();
        List<String> keys = Arrays.asList("user:{info}:id","user:{info}:age","user:{info}:name","user:{info}:email");
        Jedis jedis = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(keys.get(3)));
        try {
            Pipeline pipelined = jedis.pipelined();
            for (String key : keys) {
                pipelined.get(key);
            }
            List<Object> results = pipelined.syncAndReturnAll();
            for (Object result : results) {
                System.out.println(result);
            }
        } finally {
            jedis.close();
        }
    }

批處理結果如下,當存在重定向問題時,pipline不會拋出異常,而是直接返回異常對象,並且成功遷移的鍵能獲取到值。

redis.clients.jedis.exceptions.JedisAskDataException: ASK 5642 192.168.0.33:6380
redis.clients.jedis.exceptions.JedisAskDataException: ASK 5642 192.168.0.33:6380
peter
[email protected]

基於異常結果對象,可以獲取到對應的重定向節點信息,根據獲取到的節點信息獲取連接再次發送請求。

@Test
    public void testPiplione2(){
        JedisSlotBasedConnectionHandler connectionHandler = new JedisCluster(new HostAndPort("192.168.0.31",6380),1000,1000,5,"1234@abcd",new JedisPoolConfig()){
            public JedisSlotBasedConnectionHandler getConnectionHandler() {
                return (JedisSlotBasedConnectionHandler) super.connectionHandler;
            }
        }.getConnectionHandler();
        List<String> keys = Arrays.asList("user:{info}:id","user:{info}:age","user:{info}:name","user:{info}:email");
        Jedis jedis = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(keys.get(3)));
        try {
            Pipeline pipelined = jedis.pipelined();
            for (String key : keys) {
                pipelined.get(key);
            }
            List<Object> results = pipelined.syncAndReturnAll();
            for (int i =0 ; i<keys.size() ; i++) {
                // 鍵順序和結果順序,Pipeline嚴格按照鍵發送的順序返回結果,即使出現異常也是如此
                Object result = results.get(i);
                //判斷是否是異常結果對象
                if (result != null && result instanceof JedisAskDataException) {
                    JedisAskDataException askException = (JedisAskDataException) result;
                    //根據異常結果對象獲取節點信息
                    HostAndPort targetNode = askException.getTargetNode();
                    //根據節點信息獲取jedis連接
                    Jedis targetJedis = connectionHandler.getConnectionFromNode(targetNode);
                    try {
                        // 執行asking
                        targetJedis.asking();
                        // 獲取key並執行
                        String key = keys.get(i);
                        String targetResult = targetJedis.get(key);
                        System.out.println(targetResult);
                    } finally {
                        targetJedis.close();
                    }
                } else {
                    System.out.println(result);
                }
            }
        }finally {
            jedis.close();
        }
    }

以下是執行結果,可以看出pipline可以根據返回的異常結果對象,獲取ask重定向節點信息,發送ask請求,獲取返回結果,這點和mget不一樣,mget出現ask重定向問題時會直接拋出異常。

232132
20
peter
[email protected]

集羣環境下的批量操作場景,建議優先選擇pipline,這樣不僅可以處理slot遷移過程的ask重定向問題,還可以提高redis的IO效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章