• 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很大也是可以的,但是实际上不行;

  • 相关阅读:
    PAT 顶级 1010 Lehmer Code (35 分)
    PAT 顶级 1010 Lehmer Code (35 分)
    CCF CSP 201909-4 推荐系统
    CCF CSP 201909-4 推荐系统
    Codeforces 1251C Minimize The Integer
    Codeforces 1251C Minimize The Integer
    CCF CSP 201803-4 棋局评估
    CCF CSP 201803-4 棋局评估
    【DP_树形DP专题】题单总结
    【DP_树形DP专题】题单总结
  • 原文地址:https://www.cnblogs.com/xiao-tao/p/9797252.html
Copyright © 2020-2023  润新知