针对基于Redis Cluster的接口数据缓存删除实现

阅读更多
首先定义个工具interface,基于Java 8的实现.
主要利用了Redis Cluster的hashTags特性。详细细节可前往 https://redis.io/topics/cluster-spec的Keys hash tags章节了解。
个人建议还是看完这个规范的前半部分才好理解,为什么会出现hash tags这个东西。

package com.xxxx.cms.common.support;

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()])); } } } } }



然后后面是针对同一接口的不同分页的缓存数据的key的设置,配合hash tags 的操作。

package com.xxxxx.cms.stock.common.support;

import com.xxxxx.cms.common.support.RedisCacheSupporter;

import redis.clients.jedis.JedisCluster;

public interface CachePrefix {

	String BASE_PREFIX = "cms:stock:plate:";

	interface interfaceSpc {
		
		String PREFIX = BASE_PREFIX + "interface" + RedisCacheSupporter.SEPARATOR;
		
		static String contents(String plateCode) {
			
			return RedisCacheSupporter.hashTagsPrefix(PREFIX + "contents" + RedisCacheSupporter.SEPARATOR + plateCode + RedisCacheSupporter.SEPARATOR);
		}
		
		static void delCotentsAllCache(JedisCluster jedisClusterClient, String plateCode) {
			
			try {
				
				RedisCacheSupporter.delAllByPrefix(jedisClusterClient, contents(plateCode));
			} catch (Exception e) {
				
				e.printStackTrace();
				RedisCacheSupporter.delLoopNodesByPrefix(jedisClusterClient, contents(plateCode));
			}
		}
		
	}

}



你可能感兴趣的:(java,redis,缓存更新)