• springboot自动装配redis在pool下偶尔出现连接异常的问题


    jedis pool的配置其实是采用 org.apache.commons.pool2.impl.GenericObjectPoolConfig类的配置项。

    jedis 2.9版本代码如下:

    package redis.clients.jedis;
    
    import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
    
    public class JedisPoolConfig extends GenericObjectPoolConfig {
      public JedisPoolConfig() {
        // defaults to make your life with connection pool easier :)
        setTestWhileIdle(true);
        setMinEvictableIdleTimeMillis(60000);
        setTimeBetweenEvictionRunsMillis(30000);
        setNumTestsPerEvictionRun(-1);
      }
    }

    而springboot的自动装配中对redis连接池的配置:

    代码位置:org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool

    /**
         * Pool properties.
         */
        public static class Pool {
    
            /**
             * Max number of "idle" connections in the pool. Use a negative value to indicate
             * an unlimited number of idle connections.
             */
            private int maxIdle = 8;
    
            /**
             * Target for the minimum number of idle connections to maintain in the pool. This
             * setting only has an effect if it is positive.
             */
            private int minIdle = 0;
    
            /**
             * Max number of connections that can be allocated by the pool at a given time.
             * Use a negative value for no limit.
             */
            private int maxActive = 8;
    
            /**
             * Maximum amount of time (in milliseconds) a connection allocation should block
             * before throwing an exception when the pool is exhausted. Use a negative value
             * to block indefinitely.
             */
            private int maxWait = -1;
    
            public int getMaxIdle() {
                return this.maxIdle;
            }
    
            public void setMaxIdle(int maxIdle) {
                this.maxIdle = maxIdle;
            }
    
            public int getMinIdle() {
                return this.minIdle;
            }
    
            public void setMinIdle(int minIdle) {
                this.minIdle = minIdle;
            }
    
            public int getMaxActive() {
                return this.maxActive;
            }
    
            public void setMaxActive(int maxActive) {
                this.maxActive = maxActive;
            }
    
            public int getMaxWait() {
                return this.maxWait;
            }
    
            public void setMaxWait(int maxWait) {
                this.maxWait = maxWait;
            }
    
        }

    问题就出现了:通过spring.redis.pool.xxx的自动装配的配置key其实就比jedis的pool的配置key要少很多,当redis服务端设置了连接空闲的最大时间时,redis服务会kill掉符合条件的空闲的链接,此时客户端的连接池并不会感知连接被kill,当有代码调用pool获取连接时可能会返回一个失效的连接对象,从而导致代码报错。

    解决方案:不使用默认的装配。

     JedisPoolConfig config = new JedisPoolConfig();

    // 最小空闲连接数
    config.setMinIdle(props.getMinIdle());
    //
    最大空闲连接数 config.setMaxIdle(props.getMaxIdle()); // 连接池最大连接数 config.setMaxTotal(props.getMaxActive()); // 最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。 config.setMaxWaitMillis(props.getMaxWait()); // 在空闲时检查有效性 config.setTestWhileIdle(props.isTestWhileIdle()); // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 config.setTestOnBorrow(props.isTestOnBorrow()); // 在return给pool时,是否提前进行validate操作 config.setTestOnReturn(props.isTestOnReturn()); // 表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义 // 该值参考redis server的配置来进行配置 config.setMinEvictableIdleTimeMillis(props.getTimeout()); // 表示idle object evitor两次扫描之间的间隔时间,-1表示不开启这个task config.setTimeBetweenEvictionRunsMillis(props.getTimeout()/2); // 表示idle object evitor每次扫描的最多的对象数
    // 建议设置和maxTotal一样大,这样每次可以有效检查所有的链接.
    config.setNumTestsPerEvictionRun(props.getNumTestsPerEvictionRun());

     注意:timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis的总和应小于 数据库设置的 超时空闲失效时间

    如果将 testOnBorrow 和 testOnReturn设置为true将会加重服务的负担,降低服务的性能,最好是通过合理的配置 testWhileIdle、minEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis、numTestsPerEvictionRun来达到达到失效连接的清除工作。

  • 相关阅读:
    使用JDBC连接并操作数据库
    JDBC连接数据库的url设useSSL参数为true产生的问题
    0-1背包问题的学习及LeetCode相关习题练习
    MySQL---操作数据库
    6、Python Requests库高级操作【2】
    5、Python Requests库高级操作【1】
    4、Python 数据解析【2】
    3、Python 数据解析【1】
    Python正则re.S,re.I等作用
    2、Python 使用Requests库通用爬取数据操作
  • 原文地址:https://www.cnblogs.com/yangzhilong/p/10861376.html
Copyright © 2020-2023  润新知