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效率。