Springboot+RedisCluster配置+重写单机redis scan - Go语言中文社区

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

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_33859231/article/details/92407716
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-12 20:40:24
  • 阅读 ( 1219 )
  • 分类:Redis

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢