最近,我们使用 Java 操作 Redis 比较多,用的组件是 Jedis ,下面是一个 maven 坐标。
redis.clients
jedis
2.9.0
jar
compile
其中操作 Redis 主要使用以下3个类,
Jedis :
用于操作单节点Redis.
SharedJedis :
用于操作分片Redis 集群,较老的方式,Redis 集群下,使用 JedisCluster 进行替代。
JedisCluster :
Redis 新增加的 Redis 集群模式下的操作类。
但是 JedisCluster 从性能方面等考虑,并没有提供 Jedis 下提供的 keys 方法,
keys 方法, 主要用于 通配符 模式匹配 返回满足条件 的 key。
keys 方法 还是比较有用的。
所以我们来扩展一下。
首先,我们定义一个接口,用于我们进行功能的扩展。
接口类:
RedisClusterOperator.java
package com.redis.extend;
import java.util.Set;
/**
* Created by szh on 2018/10/16.
*
* @author szh
*/
public interface RedisClusterOperator {
Set keys(String pattern);
}
实现类:
RedisClusterExtCmd.java
package com.redis.extend.impl;
import com.redis.extend.RedisClusterOperator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Created by szh on 2018/10/16.
*
* @author szh
*/
public class RedisClusterExtCmd implements RedisClusterOperator {
public final static Logger logger = LoggerFactory.getLogger(RedisClusterOperator.class);
private JedisCluster jedisCluster = null;
public RedisClusterExtCmd(JedisCluster jedisCluster) {
this.jedisCluster = jedisCluster;
}
@Override
public Set keys(String pattern) {
logger.debug("Start getting keys... ");
TreeSet keys = new TreeSet<>();
Map clusterNodes =
jedisCluster.getClusterNodes();
for (String key : clusterNodes.keySet()) {
logger.debug("Getting keys from: {}", key);
JedisPool jedisPool = clusterNodes.get(key);
Jedis jedisConn = jedisPool.getResource();
try {
keys.addAll(jedisConn.keys(pattern));
} catch (Exception e) {
logger.error("Getting keys error: {}", e);
} finally {
logger.debug("Jedis connection closed");
jedisConn.close();
}
}
logger.debug("Keys gotten");
return keys;
}
}
实现思路:
JedisCluster 可以获取到 cluster 中所有的节点,我们对集群中每个节点都执行 keys(pattern)。
并对 keys 去重后,返回一个 set
此外,我们参考下 spring-redis 的实现,可以验证实现思路 与我们的实现思路一致。
package sunyu.example.bigdata.monitor;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class RedisTests {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void t1() {
stringRedisTemplate.keys()
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.RedisKeyCommands#keys(byte[])
*/
@Override
public Set keys(final byte[] pattern) {
Assert.notNull(pattern, "Pattern must not be null!");
Collection> keysPerNode = clusterCommandExecutor
.executeCommandOnAllNodes(new JedisClusterCommandCallback>() {
@Override
public Set doInCluster(Jedis client) {
return client.keys(pattern);
}
}).resultsAsList();
Set keys = new HashSet();
for (Set keySet : keysPerNode) {
keys.addAll(keySet);
}
return keys;
}