zoukankan      html  css  js  c++  java
  • RedisCluster集群模式下master宕机主从切换期间Lettuce连接Redis无法使用报错Redis command timed out的问题

     

    错误:

     

    原因:

    SpringBoot2.X版本开始Redis默认的连接池都是采用的Lettuce。当节点发生改变后,Letture默认是不会刷新节点拓扑的。

    方案一:把lettuce换成jedis

    只需要在pom.xml里调整一下依赖的引用

      <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <version>2.1.5.RELEASE</version>
                    <!-- 不用lettuce ,用jedis -->
                    <exclusions>
                        <exclusion>
                            <groupId>io.lettuce</groupId>
                            <artifactId>lettuce-core</artifactId>
                        </exclusion>
                    </exclusions>
            </dependency>
    
    
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>3.1.0-m4</version>
            </dependency>

    方案二:刷新节点拓扑视图

    redis节点异常,服务端的Redis集群拓扑被刷新了,java程序没有获取到新的拓扑。

    Lettuce官方文档中关于Redis Cluster的相关说明:Lettuce处理Moved和Ask永久重定向,由于命令重定向,你必须刷新节点拓扑视图。而自适应拓扑刷新(Adaptive updates)与定时拓扑刷新(Periodic updates)是默认关闭的,可以通过如下代码打开。

     

    代码如下:

    package com.montnets.common.redis;
    
    import io.lettuce.core.ClientOptions;
    import io.lettuce.core.cluster.ClusterClientOptions;
    import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.data.redis.connection.RedisClusterConfiguration;
    import org.springframework.data.redis.connection.RedisNode;
    import org.springframework.data.redis.connection.RedisPassword;
    import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
    import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
    import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
    import org.springframework.stereotype.Component;
    
    import java.time.Duration;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    /**
     * @author : harara
     * @version : 2.0
     * @date : 2020/7/27 10:19
     */
    @Component
    public class RedisPoolConfig {
    
        @Autowired
        private RedisProperties redisProperties;
    
        public GenericObjectPoolConfig<?> genericObjectPoolConfig(RedisProperties.Pool properties) {
            GenericObjectPoolConfig<?> config = new GenericObjectPoolConfig<>();
            config.setMaxTotal(properties.getMaxActive());
            config.setMaxIdle(properties.getMaxIdle());
            config.setMinIdle(properties.getMinIdle());
            if (properties.getTimeBetweenEvictionRuns() != null) {
                config.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRuns().toMillis());
            }
            if (properties.getMaxWait() != null) {
                config.setMaxWaitMillis(properties.getMaxWait().toMillis());
            }
            return config;
        }
    
        @Bean(destroyMethod = "destroy")
        public LettuceConnectionFactory lettuceConnectionFactory() {
    
            //开启 自适应集群拓扑刷新和周期拓扑刷新
            ClusterTopologyRefreshOptions clusterTopologyRefreshOptions =  ClusterTopologyRefreshOptions.builder()
                    // 开启全部自适应刷新
                    .enableAllAdaptiveRefreshTriggers() // 开启自适应刷新,自适应刷新不开启,Redis集群变更时将会导致连接异常
                    // 自适应刷新超时时间(默认30秒)
                    .adaptiveRefreshTriggersTimeout(Duration.ofSeconds(30)) //默认关闭开启后时间为30秒
                    // 开周期刷新
                    .enablePeriodicRefresh(Duration.ofSeconds(20))  // 默认关闭开启后时间为60秒 ClusterTopologyRefreshOptions.DEFAULT_REFRESH_PERIOD 60  .enablePeriodicRefresh(Duration.ofSeconds(2)) = .enablePeriodicRefresh().refreshPeriod(Duration.ofSeconds(2))
                    .build();
    
            // https://github.com/lettuce-io/lettuce-core/wiki/Client-Options
            ClientOptions clientOptions = ClusterClientOptions.builder()
                    .topologyRefreshOptions(clusterTopologyRefreshOptions)
                    .build();
    
            LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
                    .poolConfig(genericObjectPoolConfig(redisProperties.getJedis().getPool()))
                    //.readFrom(ReadFrom.MASTER_PREFERRED)
                    .clientOptions(clientOptions)
                    .commandTimeout(redisProperties.getTimeout()) //默认RedisURI.DEFAULT_TIMEOUT 60
                    .build();
    
            List<String> clusterNodes = redisProperties.getCluster().getNodes();
            Set<RedisNode> nodes = new HashSet<RedisNode>();
            clusterNodes.forEach(address -> nodes.add(new RedisNode(address.split(":")[0].trim(), Integer.valueOf(address.split(":")[1]))));
    
            RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration();
            clusterConfiguration.setClusterNodes(nodes);
            clusterConfiguration.setPassword(RedisPassword.of(redisProperties.getPassword()));
            clusterConfiguration.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
    
            LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, clientConfig);
            // lettuceConnectionFactory.setShareNativeConnection(false); //是否允许多个线程操作共用同一个缓存连接,默认true,false时每个操作都将开辟新的连接
            // lettuceConnectionFactory.resetConnection(); // 重置底层共享连接, 在接下来的访问时初始化
            return lettuceConnectionFactory;
        }
    }

    参考地址:

    RedisCluster集群模式下master宕机主从切换期间Lettuce连接Redis无法使用报错Redis command timed out的问题 : https://blog.csdn.net/u010046887/article/details/106948341

  • 相关阅读:
    JS使用 popstate 事件监听物理返回键
    JQ判断div是否隐藏
    SQL Server DATEDIFF() 函数
    取消a或input标签聚焦后出现虚线框
    C#定时任务
    C# 保留N位小数
    C#打印单据
    SQL语句创建函数
    SVN检出新项目
    解决jQuery的toggle()的自动触发问题
  • 原文地址:https://www.cnblogs.com/kiko2014551511/p/13383983.html
Copyright © 2011-2022 走看看