Implementation of interface data cache deletion based on Redis Cluster

First define a tool interface, based on the implementation of Java 8.
It mainly uses the hashTags feature of Redis Cluster. Details can be found in the Keys hash tags chapter of https://redis.io/topics/cluster-spec .
My personal suggestion is to read the first half of this specification to understand why hash tags appear.

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<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;
	}
	
	/**
	 * This method is preferred for keys whose cache prefix is ​​processed by hash tags {@link #hashTagsPrefix(String)}
	 * <br/>
	 * <br/>
	 * Hash tags cannot be guaranteed to be in the same slot when reSharding in a redis cluster, so for the sake of code robustness, this method can be called first, and then the {@link #delLoopNodesByPrefix(JedisCluster, String)} method can be called to handle exceptions.
	 * @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;// The slave node does not process

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

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

					// When performing multiple key operations in cluster mode, these keys must be in the same slot
					// Otherwise, it will report: redis.clients.jedis.exceptions.JedisClusterException:
					// No way to dispatch this command to Redis Cluster because keys have different slots.
					int slot = JedisClusterCRC16.getSlot(key);
					// Group keys by slot, and submit keys of the same slot together
					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()]));
				}
			}
		}
	}
	
}




Then there is the key setting of the cached data for different pages of the same interface, in conjunction with the operation of 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));
			}
		}
		
	}

}



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326184577&siteId=291194637