方便jedis cluster操作的工具类

由于redis的集群 redis cluster不支持keys这样的多key操作(具体原因由于sharding 后,不同的key属于不同的slot,难以支持原子操作)。所以如果一个对外需要对缓存做失效处理时比较棘手。所以本类提供工具方法再redis cluster查找按照hashTags处理的keys和一般的keys。基于jedis cluster实现。

有优化空间,现在懒得改了



import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.commons.collections4.CollectionUtils;

import com.google.common.collect.Lists;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.util.JedisClusterCRC16;

public interface RedisCacheSupporter {

String SEPARATOR = RedisCacheBase.staticSeparator();

String CONJUNCTION = RedisCacheBase.staticConjunction();

String PLACEHOLDER = RedisCacheBase.staticPlaceHolder();

String LEFT_TAG_STR = RedisCacheBase.staticLeftTagStr();

String RIGHT_TAG_STR = RedisCacheBase.staticRightTagStr();

static String hashTagsPrefix(String cacheKeyPrefix) {

return LEFT_TAG_STR + cacheKeyPrefix + RIGHT_TAG_STR;
}

static TreeSet keys(JedisCluster jedisClusterClient, String cachePrefix) {

Map clusterNodes = jedisClusterClient.getClusterNodes();
TreeSet keys = new TreeSet<>();
String strPattern = cachePrefix + "*";
for (String k : clusterNodes.keySet()) {

JedisPool jp = clusterNodes.get(k);
try (Jedis jedis = jp.getResource();) {

if (jedis.info("replication").contains("role:slave"))
continue;

Set keysInNode = jedis.keys(strPattern);
keys.addAll(keysInNode);
}
}
return keys;
}

static boolean delByKey(JedisCluster jedisClusterClient, String cacheKey) {

return jedisClusterClient.del(cacheKey) > 0;
}

/**
* 缓存前缀通过hash tags {@link #hashTagsPrefix(String)}处理过的key首选使用本方法
*

*

* hash tags在redis集群reSharding时,不能保证都在同一slot下,所以为代码健壮性考虑可首先调用本方法再捕获异常中调用{@link #delLoopNodesByPrefix(JedisCluster, String)}方法处理
* @param jedisClusterClient
* @param cachePrefix
*/
static void delAllByPrefix(JedisCluster jedisClusterClient, String cachePrefix) {

Set keys = keys(jedisClusterClient, cachePrefix);
if (CollectionUtils.isEmpty(keys)) {

return;
}

jedisClusterClient.del(keys.toArray(new String[keys.size()]));
}

static void delLoopNodesByPrefix(JedisCluster jedisClusterClient, String cachePrefix) {

String keysPattern = cachePrefix + "*";
Map clusterNodes = jedisClusterClient.getClusterNodes();
for (String k : clusterNodes.keySet()) {

JedisPool jedisPool = clusterNodes.get(k);
try (Jedis jedis = jedisPool.getResource()) {

if (jedis.info("replication").contains("role:slave"))
continue;// 从节点不处理

Set keys = jedis.keys(keysPattern);
if (keys.size() <= 0)
continue;

Map> map = new HashMap<>();
for (String key : keys) {

// cluster模式执行多key操作的时候,这些key必须在同一个slot上
// 不然会报:redis.clients.jedis.exceptions.JedisClusterException:
// No way to dispatch this command to Redis Cluster because keys have different slots.
int slot = JedisClusterCRC16.getSlot(key);
// 按slot将key分组,相同slot的key一起提交
if (map.containsKey(slot)) {
map.get(slot).add(key);
} else {
map.put(slot, Lists.newArrayList(key));
}
}

for (Integer slotKey : map.keySet()) {
jedis.del(map.get(slotKey).toArray(new String[map.get(slotKey).size()]));
}
}
}
}

}

你可能感兴趣的:(技术技巧)