Springboot+RedisCluster配置+重写单机redis scan

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<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.

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开头的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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值