分别使用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
132132@163.com
基于异常结果对象,可以获取到对应的重定向节点信息,根据获取到的节点信息获取连接再次发送请求。
@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
132132@163.com
集群环境下的批量操作场景,建议优先选择pipline,这样不仅可以处理slot迁移过程的ask重定向问题,还可以提高redis的IO效率。