jedis連接池參數minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis探索


我們通常在使用JedisPoolConfig進行連接池配置的時候,minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis這兩個參數經常會不懂其含義,
查各種資料也沒有非常明確的說到底該如何設置,即使知道如何設置,也不知道其原理,只知道這兩個參數是和逐出線程有關的。下面根據源碼進行探索。
我們通常是通過JedisPool構造線程池,追溯其父類的創建過程,發現Pool<T>這個泛型類的構造方法調用過程如下:

public Pool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
        this.initPool(poolConfig, factory);
    }

public void initPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory<T> factory) {
        if(this.internalPool != null) {
            try {
                this.closeInternalPool();
            } catch (Exception var4) {
                ;
            }
        }

        this.internalPool = new GenericObjectPool(factory, poolConfig);
    }

發現其創建了一個GenericObjectPool對象,構造方法如下:

public GenericObjectPool(PooledObjectFactory<T> factory, GenericObjectPoolConfig config) {
        super(config, "org.apache.commons.pool2:type=GenericObjectPool,name=", config.getJmxNamePrefix());
        this.factoryType = null;
        this.maxIdle = 8;
        this.minIdle = 0;
        this.allObjects = new ConcurrentHashMap();
        this.createCount = new AtomicLong(0L);
        this.abandonedConfig = null;
        if(factory == null) {
            this.jmxUnregister();
            throw new IllegalArgumentException("factory may not be null");
        } else {
            this.factory = factory;
            this.idleObjects = new LinkedBlockingDeque(config.getFairness());
            this.setConfig(config);
            this.startEvictor(this.getTimeBetweenEvictionRunsMillis());
        }
    }

其中this.startEvictor(this.getTimeBetweenEvictionRunsMillis());方法的調用,正是開啟逐出線程運行的作用,

我們可以發現,源碼通過周期性的調度逐出任務(timeBetweenEvictionRunsMillis大於0時),將空閑的連接逐出線程池。

final void startEvictor(long delay) {
        Object var3 = this.evictionLock;
        synchronized(this.evictionLock) {
            if(null != this.evictor) {
                EvictionTimer.cancel(this.evictor);
                this.evictor = null;
                this.evictionIterator = null;
            }

            if(delay > 0L) {
                this.evictor = new BaseGenericObjectPool.Evictor();
                EvictionTimer.schedule(this.evictor, delay, delay);
            }

        }
    }

下面將是我們今天研究的重點,this.evictor。

逐出有逐出策略,如果不配置則采用默認的逐出策略DefaultEvictionPolicy,其中的evict方法返回true時才執行逐出的操作

public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {
    public DefaultEvictionPolicy() {
    }

    public boolean evict(EvictionConfig config, PooledObject<T> underTest, int idleCount) {
        return config.getIdleSoftEvictTime() < underTest.getIdleTimeMillis() && config.getMinIdle() < idleCount || config.getIdleEvictTime() < underTest.getIdleTimeMillis();
    }
}

真正的逐出方法執行的是以下內容

public void evict() throws Exception {
        this.assertOpen();
        if(this.idleObjects.size() > 0) {
            PooledObject<T> underTest = null;
            EvictionPolicy<T> evictionPolicy = this.getEvictionPolicy();
            Object var3 = this.evictionLock;
            synchronized(this.evictionLock) {
                EvictionConfig evictionConfig = new EvictionConfig(this.getMinEvictableIdleTimeMillis(), this.getSoftMinEvictableIdleTimeMillis(), this.getMinIdle());
                boolean testWhileIdle = this.getTestWhileIdle();
                int i = 0;
                int m = this.getNumTests();

                while(true) {
                    if(i >= m) {
                        break;
                    }

                    if(this.evictionIterator == null || !this.evictionIterator.hasNext()) {
                        this.evictionIterator = new EvictionIterator(this, this.idleObjects);
                    }

                    if(!this.evictionIterator.hasNext()) {
                        return;
                    }

                    label81: {
                        try {
                            underTest = this.evictionIterator.next();
                        } catch (NoSuchElementException var15) {
                            --i;
                            this.evictionIterator = null;
                            break label81;
                        }

                        if(!underTest.startEvictionTest()) {
                            --i;
                        } else {
                            boolean evict;
                            try {
                                evict = evictionPolicy.evict(evictionConfig, underTest, this.idleObjects.size());
                            } catch (Throwable var14) {
                                PoolUtils.checkRethrow(var14);
                                this.swallowException(new Exception(var14));
                                evict = false;
                            }

                            if(evict) {
                                this.destroy(underTest);
                                this.destroyedByEvictorCount.incrementAndGet();
                            } else {
                                if(testWhileIdle) {
                                    boolean active = false;

                                    try {
                                        this.factory.activateObject(underTest);
                                        active = true;
                                    } catch (Exception var13) {
                                        this.destroy(underTest);
                                        this.destroyedByEvictorCount.incrementAndGet();
                                    }

                                    if(active) {
                                        if(!this.factory.validateObject(underTest)) {
                                            this.destroy(underTest);
                                            this.destroyedByEvictorCount.incrementAndGet();
                                        } else {
                                            try {
                                                this.factory.passivateObject(underTest);
                                            } catch (Exception var12) {
                                                this.destroy(underTest);
                                                this.destroyedByEvictorCount.incrementAndGet();
                                            }
                                        }
                                    }
                                }

                                if(!underTest.endEvictionTest(this.idleObjects)) {
                                    ;
                                }
                            }
                        }
                    }

                    ++i;
                }
            }
        }

        AbandonedConfig ac = this.abandonedConfig;
        if(ac != null && ac.getRemoveAbandonedOnMaintenance()) {
            this.removeAbandoned(ac);
        }

    }

我們重點看兩行代碼,第8行是創建了逐出配置,根據你配置的minEvictableIdleTimeMillis和softMinEvictableIdleTimeMillis,如果存在負數,則設為long類型的最大值。

public EvictionConfig(long poolIdleEvictTime, long poolIdleSoftEvictTime, int minIdle) {
        if(poolIdleEvictTime > 0L) {
            this.idleEvictTime = poolIdleEvictTime;
        } else {
            this.idleEvictTime = 9223372036854775807L;
        }

        if(poolIdleSoftEvictTime > 0L) {
            this.idleSoftEvictTime = poolIdleSoftEvictTime;
        } else {
            this.idleSoftEvictTime = 9223372036854775807L;
        }

        this.minIdle = minIdle;
    }

再看第40行代碼,再結合DefaultEvictionPolicy的evict方法,我們可以看到,真正的逐出依據是:

1.連接空閑時間大於softMinEvictableIdleTimeMillis並且當前連接池的空閑連接數大於最小空閑連接數minIdle;

2.連接空閑時間大於minEvictableIdleTimeMillis。

1或者2成立即可逐出,注意是或的關系。

所以,結論如下:

如果要連接池只根據softMinEvictableIdleTimeMillis進程逐出,那么需要將minEvictableIdleTimeMillis設置為負數(即最大值);
如果要連接池只根據minEvictableIdleTimeMillis進程逐出,那么需要將softMinEvictableIdleTimeMillis設置為負數(即最大值),理論上設置minIdle很大也是可以的,但是實際上不行;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM