方便jedis cluster操作的工具类
程序员文章站
2022-03-21 23:40:33
...
由于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<String> keys(JedisCluster jedisClusterClient, String cachePrefix) { Map<String, JedisPool> clusterNodes = jedisClusterClient.getClusterNodes(); TreeSet<String> 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<String> 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首选使用本方法 * <br/> * <br/> * hash tags在redis集群reSharding时,不能保证都在同一slot下,所以为代码健壮性考虑可首先调用本方法再捕获异常中调用{@link #delLoopNodesByPrefix(JedisCluster, String)}方法处理 * @param jedisClusterClient * @param cachePrefix */ static void delAllByPrefix(JedisCluster jedisClusterClient, String cachePrefix) { Set<String> 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<String, JedisPool> 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<String> keys = jedis.keys(keysPattern); if (keys.size() <= 0) continue; Map<Integer, List<String>> 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()])); } } } } }
上一篇: 西安小吃美食有哪些,你都吃过了吗?