Springboot配置RedisCLuster集群跟单机的玩法有很多不一样.
资源文件
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 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.
public class RedisUntil {
public static List getScan(Jedis redisService,String key) {
List 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 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 getRedisKeys(JedisCluster jedisCluster,String matchKey) {
List list = new ArrayList<>();
try {
Map clusterNodes = jedisCluster.getClusterNodes();
for (Map.Entry entry : clusterNodes.entrySet()) {
Jedis jedis = entry.getValue().getResource();
// 判断非从节点(因为若主从复制,从节点会跟随主节点的变化而变化)
if (!jedis.info("replication").contains("role:slave")) {
List keys = getScan(jedis,matchKey);
if (keys.size() > 0) {
Map> 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> 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开头的key
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>
则访问返回值为
["a","a1"]
转自:https://my.oschina.net/u/3768341/blog/2223336
https://brandnewuser.iteye.com/blog/2323778