springboot自動裝配redis在pool下偶爾出現鏈接異常的問題

jedis pool的配置實際上是採用 org.apache.commons.pool2.impl.GenericObjectPoolConfig類的配置項。redis

jedis 2.9版本代碼以下:spring

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

/**
     * 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獲取鏈接時可能會返回一個失效的鏈接對象,從而致使代碼報錯。springboot

解決方案:不使用默認的裝配。性能

 JedisPoolConfig config = new JedisPoolConfig();// 最小空閒鏈接數config.setMinIdle(props.getMinIdle());this

// 最大空閒鏈接數 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的總和應小於 數據庫設置的 超時空閒失效時間spa

若是將 testOnBorrow 和 testOnReturn設置爲true將會加劇服務的負擔,下降服務的性能,最好是經過合理的配置 testWhileIdle、minEvictableIdleTimeMillis、timeBetweenEvictionRunsMillis、numTestsPerEvictionRun來達到達到失效鏈接的清除工做。code

相關文章
相關標籤/搜索