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

https://brandnewuser.iteye.com/blog/2323778

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,你需要在 Spring Boot 项目中添加 Redis 的依赖,可以使用以下 Maven 依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 接着,在 application.properties 或 application.yml 文件中添加 Redis配置: ```yaml # Redis 主节点配置 spring.redis.host=127.0.0.1 spring.redis.port=6379 # Redis 从节点配置 spring.redis.cluster.nodes=192.168.1.1:6379,192.168.1.2:6379 spring.redis.cluster.master=master ``` 以上配置是一个 Redis 主节点和两个从节点的示例,其中: - `spring.redis.host` 和 `spring.redis.port` 是主节点的地址和端口。 - `spring.redis.cluster.nodes` 是从节点的地址和端口列表,多个节点使用英文逗号分隔。 - `spring.redis.cluster.master` 是主节点的名称,可以在 Redis 配置文件中设置。 最后,你需要使用 RedisTemplate 或者 StringRedisTemplate 类来操作 Redis。在 Spring Boot 中,你可以通过注入 RedisTemplate 或者 StringRedisTemplate 类来使用 Redis。例如: ```java @Autowired private RedisTemplate<String, Object> redisTemplate; public void set(String key, Object value) { redisTemplate.opsForValue().set(key, value); } public Object get(String key) { return redisTemplate.opsForValue().get(key); } ``` 以上代码中,我们注入了 RedisTemplate 类,并使用其 `opsForValue` 方法来操作 Redis 中的数据。 注意,如果你使用的是 Redis 主从复制模式,你在写入数据时应该使用主节点,而在读取数据时可以使用主节点或从节点。如果你使用的是 Redis 集群模式,Spring Boot 会自动将读取操作负载均衡到不同的节点上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值