最近项目上了Redis集群,有相关的业务地方使用到了pipelineget(),之前是单节点,上了集群之后,发现java.lang.UnsupportedoperationException:Pipeline iscurrentlvsupported for JedisClusterConnection
,下方异常是我在内部ELK系统上查询到的
解决方案:
思想架构:
1.获取每个节点上可以分配到的key
private Map<RedisClusterNode, List<String>> getNodeKeyMap(Collection<String> keys, RedisClusterConnection redisClusterConnection) {
//定义的map以redis的节点为key list为value,此处的list存放的该节点下需要存储的key值
HashMap<RedisClusterNode, List<String>> nodeKeyMap = new HashMap<>(8);
//通过计算每个key的槽点,获取所有的节点
Iterable<RedisClusterNode> redisClusterNodes = redisClusterConnection.clusterGetNodes();
for (RedisClusterNode redisClusterNode : redisClusterNodes) {
//得到节点的槽位的范围
RedisClusterNode.SlotRange slotRange = redisClusterNode.getSlotRange();
for (String key : keys) {
//利用redis的key的hash算法得到该key对应的槽位
int slot = JedisClusterCRC16.getSlot(key);
if (slotRange.contains(slot)) {
List<String> list = nodeKeyMap.get(redisClusterNode);
if (null == list) {
list = new ArrayList<>();
nodeKeyMap.putIfAbsent(redisClusterNode, list);
}
//将对应的key放入进去
list.add(key);
}
}
}
return nodeKeyMap;
}
2.获取连接,打开pipeline,执行get/set操作
public void clusterPipelineSet(Map<String, Object> data) {
Set<String> keys = data.keySet();
//获取key的序列化策略
RedisSerializer keySerializer = redisTemplate.getKeySerializer();
RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
//获取集群的连接对象
RedisClusterConnection redisClusterConnection = redisTemplate.getConnectionFactory().getClusterConnection();
try {
Map<RedisClusterNode, List<String>> nodeKeyMap = getNodeKeyMap(keys, redisClusterConnection);
//开始遍历通过管道往redis中放入数据 遍历上边定义的map
for (Map.Entry<RedisClusterNode, List<String>> clusterNodeListEntry : nodeKeyMap.entrySet()) {
//连接节点
RedisClusterNode redisClusterNode = clusterNodeListEntry.getKey();
//获取到每个节点的JedisPool对象 关于jedis和redistemplate的关系下边会进行简单介绍。
JedisPool jedisPool = ((JedisCluster) redisClusterConnection.getNativeConnection()).getClusterNodes()
.get(new HostAndPort(redisClusterNode.getHost(), redisClusterNode.getPort()).toString());
List<String> nodeListEntryValue = clusterNodeListEntry.getValue();
//从池子中拿出对应的jedis对象
Jedis jedis = jedisPool.getResource();
try {
//开始使用单节点的pipline对象进行操作。
Pipeline pipeline = jedis.pipelined();
//************************接下来的操作就是对应利用pipline获取值和set值可以根据业务需求选取******************************
//往redis中放入值
for (String nodeKey : nodeListEntryValue) {
pipeline.set(keySerializer.serialize(nodeKey), valueSerializer.serialize(data.get(nodeKey)));
}
pipeline.sync();
//*************************************************************************************************************
pipeline.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
jedis.close();
}
}
} finally {
RedisConnectionUtils.releaseConnection(redisClusterConnection, redisTemplate.getConnectionFactory());
}
}
public List<Object> clusterPiplineGet(List<String> keys) throws Exception {
//获取key的序列化策略
RedisSerializer keySerializer = redisTemplate.getKeySerializer();
List<Object> result = new ArrayList<>(8);
//获取集群的连接对象
RedisClusterConnection redisClusterConnection = redisTemplate.getConnectionFactory().getClusterConnection();
try {
Map<RedisClusterNode, List<String>> nodeKeyMap = getNodeKeyMap(keys, redisClusterConnection);
//开始遍历通过管道往redis中放入数据 遍历上边定义的map
for (Map.Entry<RedisClusterNode, List<String>> clusterNodeListEntry : nodeKeyMap.entrySet()) {
//连接节点
RedisClusterNode redisClusterNode = clusterNodeListEntry.getKey();
//获取到每个节点的JedisPool对象 关于jedis和redistemplate的关系下边会进行简单介绍。
JedisPool jedisPool = ((JedisCluster) redisClusterConnection.getNativeConnection()).getClusterNodes()
.get(new HostAndPort(redisClusterNode.getHost(), redisClusterNode.getPort()).toString());
List<String> nodeListEntryValue = clusterNodeListEntry.getValue();
//从池子中拿出对应的jedis对象
Jedis jedis = jedisPool.getResource();
List<Response<byte[]>> responses = new ArrayList<>();
try {
//开始使用单节点的pipline对象进行操作。
Pipeline pipeline = jedis.pipelined();
//************************接下来的操作就是对应利用pipline获取值和set值可以根据业务需求选取******************************
//从redis中获取值
for (String nodeKey : nodeListEntryValue) {
responses.add(pipeline.get(keySerializer.serialize(nodeKey)));
}
List<Object> objects = pipeline.syncAndReturnAll();
if (!CollectionUtils.isEmpty(objects)) {
result.addAll(objects);
}
pipeline.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
jedis.close();
}
}
} finally {
RedisConnectionUtils.releaseConnection(redisClusterConnection, redisTemplate.getConnectionFactory());
}
return result.stream().filter(r -> Objects.nonNull(r)).collect(Collectors.toList());
}
3.Test测试类
@Test
public void testClusterPipeline() throws Exception {
List<String> keys = Lists.newArrayList("aa1", "bb1","cc1");
List<Object> objects = taRedisService.clusterPiplineGet(keys);
System.out.println("objects = " + objects);
for (Object object : objects) {
byte[] b = (byte[]) object;
String s = new String(b, CharsetUtil.UTF_8);
System.out.println("s = " + s);
}
}
@Test
public void testClusterPipelineSet() {
Map<String, Object> data = new HashMap<>();
data.put("aa1", "v1");
data.put("bb1", "v2");
data.put("cc1", "v3");
taRedisService.clusterPipelineSet(data);
}