Redis集群使用keys命令搜索匹配的Key
目录
Redis集群使用keys命令搜索匹配的Key
需求
今天在项目过程中碰到了一个需求:
1.所有节点(数量在1~10万)都会存储一个在线状态的Key在Redis集群,3分钟失效, 收到节点上报的任何数据后,刷新这个缓存。
2.需定时查询所有节点在Redis的状态,并将节点状态同步到数据库。
问题
因为Redis只有顶级的Key才可以设置超时时间,所以无法使用hset,hgetAll命令一次
性获取所有的节点信息,只有使用get(key)方法一个一个获取设备的在线状态,由于
Redis是单线程应用,这就造成了比较严重的性能问题。
经测试循环获取8万个节点的在线状态,耗时会达到50s左右,这是完全无法容忍的。
而项目中为保证可靠性,使用的是Redis集群,Redis操作都必须通过JedisCluster的
接口来实现,故而也无法使用Jedis的keys(pattern)方法来一次性搜索所有的在线节
点的Key。
解决思路
网络上搜索了一些解决方法,都感觉有些复杂,所以自己考虑是否可以用更简单的方
式解决这个问题。
思路是Redis集群有6个节点,其中有3个主节点,每个主节点各自有一个从节点,其
实只需要将集群视为3个单独的Redis,分别用keys(pattern)方法搜索各自的key,然
后把3次搜索的结果相加,就是集群内所有的Key了。
JedisCluster在网上的API很少,进去这个类看了一下,发现有一个方法:
Map<String,JedisPool> getClusterNodes();
复制代码
根据方法名和返回值判断,这应该就是我要找的获取Redis集群所有节点的方法了,
写了个方法测试了一下,果然可以拿到集群内所有的节点,那剩下的事情就好办了。
最终的搜索集群内匹配的Key方法如下:
/**
* 搜索集群内匹配的Key
*
* @param pattern 匹配规则,该参数和Jedis keys(pattern)方法相同。
* eg:搜索Node_status_开头的所有key,该参数填Node_status_*
* @return 集群内所有符合规则的Key列表
*/
public Set<String> clusterKeys(String pattern)throws DataLoadException{
Set<String> result = new HashSet<>();
try {
// 获取Redis集群内所有节点
Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
Jedis jedis = entry.getValue().getResource();
// 判断非从节点(因为若主从复制,从节点会跟随主节点的变化而变化)
if (!jedis.info("replication").contains("role:slave")) {
// 搜索单个节点内匹配的Key
Set<String> keys = jedis.keys(pattern);
// 合并搜索结果
result.addAll(keys);
}
jedis.close();
}
} catch (Exception e) {
throw new DataLoadException(e);
} finally {
returnJedisCluster(jedisCluster);
}
return result;
}
复制代码
经测试,该方法一次性搜索 8 万个节点的在线状态,耗时在 100ms 左右。