Springboot配置RedisCLuster集羣跟單機的玩法有不少不同.node
資源文件redis
redis: cache: clusterNodes: 192.168.5.182:7111,192.168.5.182:7112,192.168.5.182:7113,192.168.5.129:7114,192.168.5.129:7115,192.168.5.129:7116 commandTimeout: 2000 expireSeconds: 100
兩個配置文件數組
@Component @Data @ConfigurationProperties(prefix = "redis.cache") public class RedisProperties { private int expireSeconds; private String clusterNodes; private int commandTimeout; }
@Configuration public class JedisClusterConfig { @Autowired private RedisProperties redisProperties; /** * 注意: * 這裏返回的JedisCluster是單例的,而且能夠直接注入到其餘類中去使用 * @return */ @Bean public JedisCluster getJedisCluster() { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(100); poolConfig.setMaxIdle(20); poolConfig.setMinIdle(10); poolConfig.setBlockWhenExhausted(true); poolConfig.setMaxWaitMillis(3000); poolConfig.setTestOnBorrow(false); poolConfig.setTestOnReturn(false); poolConfig.setTestWhileIdle(true); poolConfig.setMinEvictableIdleTimeMillis(60000); poolConfig.setTimeBetweenEvictionRunsMillis(30000); poolConfig.setNumTestsPerEvictionRun(-1); String[] serverArray = redisProperties.getClusterNodes().split(",");//獲取服務器數組(這裏要相信本身的輸入,因此沒有考慮空指針問題) Set<HostAndPort> nodes = new HashSet<>(); for (String ipPort : serverArray) { String[] ipPortPair = ipPort.split(":"); nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim()))); } return new JedisCluster(nodes, redisProperties.getCommandTimeout(),redisProperties.getExpireSeconds(),poolConfig); } }
這樣咱們就能夠直接使用JedisCluster來進行集羣操做.服務器
可是JedisCluster並不支持對單機scan操做,因此咱們獲取模糊匹配的List的時候須要改寫.整體思路就是獲取Redis集羣的各個slot節點,再用scan命令以單機形式獲取各個節點的key,最後就獲取了全部節點的key.app
public class RedisUntil { public static List<String> getScan(Jedis redisService,String key) { List<String> list = new ArrayList<>(); ScanParams params = new ScanParams(); params.match(key); params.count(100); String cursor = "0"; while (true) { ScanResult scanResult = redisService.scan(cursor,params); List<String> elements = scanResult.getResult(); if (elements != null && elements.size() > 0) { list.addAll(elements); } cursor = scanResult.getStringCursor(); if ("0".equals(cursor)) { break; } } return list; } public static List<String> getRedisKeys(JedisCluster jedisCluster,String matchKey) { List<String> list = new ArrayList<>(); try { 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")) { List<String> keys = getScan(jedis,matchKey); if (keys.size() > 0) { Map<Integer, List<String>> map = new HashMap<>(); for (String key : keys) { // cluster模式執行多key操做的時候,這些key必須在同一個slot上,否則會報:JedisDataException: // CROSSSLOT Keys in request don't hash to the same slot 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 (Map.Entry<Integer, List<String>> integerListEntry : map.entrySet()) { // System.out.println("integerListEntry="+integerListEntry); list.addAll(integerListEntry.getValue()); } } } } } finally { return list; } } }
假如咱們隨便寫一個controller指針
@Autowired private JedisCluster jedis;
@GetMapping("/users-anon/get") public List getRedisCLuster() { return RedisUntil.getRedisKeys(jedis,"a*"); }
假設咱們redis集羣中有2個帶a開頭的keyserver
192.168.5.182:7112> get a1
-> Redirected to slot [7785] located at 192.168.5.182:7113
"bb"
192.168.5.182:7113> get a
-> Redirected to slot [15495] located at 192.168.5.182:7112
"b"
192.168.5.182:7112> ip
則訪問返回值爲element
["a","a1"]