本文次要钻研一下jedis连接池的参数配置

JedisConfig

redis/clients/jedis/JedisPoolConfig.java

public class JedisPoolConfig extends GenericObjectPoolConfig<Jedis> {  public JedisPoolConfig() {    // defaults to make your life with connection pool easier :)    setTestWhileIdle(true);    setMinEvictableIdleTimeMillis(60000);    setTimeBetweenEvictionRunsMillis(30000);    setNumTestsPerEvictionRun(-1);  }}
JedisPoolConfig继承了GenericObjectPoolConfig,同时默认配置了testWhileIdle为true(默认为false),minEvictableIdleTime为60s(默认为30分钟),timeBetweenEvictionRuns为30s(默认为-1),numTestsPerEvictionRun为-1(即检测所有闲暇连贯,默认值为3)

GenericObjectPoolConfig

org/apache/commons/pool2/impl/GenericObjectPoolConfig.java

public class GenericObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {    /**     * The default value for the {@code maxTotal} configuration attribute.     * @see GenericObjectPool#getMaxTotal()     */    public static final int DEFAULT_MAX_TOTAL = 8;    /**     * The default value for the {@code maxIdle} configuration attribute.     * @see GenericObjectPool#getMaxIdle()     */    public static final int DEFAULT_MAX_IDLE = 8;    /**     * The default value for the {@code minIdle} configuration attribute.     * @see GenericObjectPool#getMinIdle()     */    public static final int DEFAULT_MIN_IDLE = 0;    private int maxTotal = DEFAULT_MAX_TOTAL;    private int maxIdle = DEFAULT_MAX_IDLE;    private int minIdle = DEFAULT_MIN_IDLE;}
GenericObjectPoolConfig继承了BaseObjectPoolConfig,其maxTotal为8,maxIdle为8,minIdle为0

BaseObjectPoolConfig

org/apache/commons/pool2/impl/BaseObjectPoolConfig.java

public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Cloneable {    private boolean lifo = DEFAULT_LIFO;    public static final boolean DEFAULT_LIFO = true;    private boolean fairness = DEFAULT_FAIRNESS;    public static final boolean DEFAULT_FAIRNESS = false;    private Duration maxWaitDuration = DEFAULT_MAX_WAIT;    public static final Duration DEFAULT_MAX_WAIT = Duration.ofMillis(-1L);    private Duration minEvictableIdleDuration = DEFAULT_MIN_EVICTABLE_IDLE_TIME;    public static final Duration DEFAULT_MIN_EVICTABLE_IDLE_TIME =            Duration.ofMillis(1000L * 60L * 30L);    private Duration evictorShutdownTimeoutDuration = DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT;    public static final Duration DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT =            Duration.ofMillis(10L * 1000L);    private Duration softMinEvictableIdleDuration = DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME;    public static final Duration DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME =            Duration.ofMillis(-1);    private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;    public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;    private EvictionPolicy<T> evictionPolicy; // Only 2.6.0 applications set this    private String evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME;    public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = DefaultEvictionPolicy.class.getName();    private boolean testOnCreate = DEFAULT_TEST_ON_CREATE;    public static final boolean DEFAULT_TEST_ON_CREATE = false;    private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;    public static final boolean DEFAULT_TEST_ON_BORROW = false;    private boolean testOnReturn = DEFAULT_TEST_ON_RETURN;    public static final boolean DEFAULT_TEST_ON_RETURN = false;    private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;    public static final boolean DEFAULT_TEST_WHILE_IDLE = false;    private Duration durationBetweenEvictionRuns = DEFAULT_TIME_BETWEEN_EVICTION_RUNS;    public static final Duration DEFAULT_TIME_BETWEEN_EVICTION_RUNS = Duration            .ofMillis(-1L);    private boolean blockWhenExhausted = DEFAULT_BLOCK_WHEN_EXHAUSTED;    public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;    private boolean jmxEnabled = DEFAULT_JMX_ENABLE;    public static final boolean DEFAULT_JMX_ENABLE = true;    // TODO Consider changing this to a single property for 3.x    private String jmxNamePrefix = DEFAULT_JMX_NAME_PREFIX;    public static final String DEFAULT_JMX_NAME_PREFIX = "pool";    private String jmxNameBase = DEFAULT_JMX_NAME_BASE;    public static final String DEFAULT_JMX_NAME_BASE = null;}
BaseObjectPoolConfig定义了lifo(默认为true)、fairness(默认为false)、maxWaitDuration(默认为-1)、minEvictableIdleDuration(默认为30分钟)、evictorShutdownTimeoutDuration(默认为10s)、softMinEvictableIdleDuration(默认为-1)、numTestsPerEvictionRun(默认为3)、evictionPolicyClassName(默认为DefaultEvictionPolicy.class.getName())、testOnCreate(默认为false)、testOnBorrow(默认为false)、testOnReturn(默认为false)、testWhileIdle(默认为false)、durationBetweenEvictionRuns(默认为-1)、blockWhenExhausted(默认为true)、jmxEnabled(默认为true)、jmxNamePrefix(默认为pool)、jmxNameBase(默认为null)

maxWaitDuration

org/apache/commons/pool2/impl/GenericObjectPool.java

            if (blockWhenExhausted) {                if (p == null) {                    if (borrowMaxWaitDuration.isNegative()) {                        p = idleObjects.takeFirst();                    } else {                        p = idleObjects.pollFirst(borrowMaxWaitDuration);                    }                }                if (p == null) {                    throw new NoSuchElementException(appendStats(                            "Timeout waiting for idle object, borrowMaxWaitDuration=" + borrowMaxWaitDuration));                }            }
borrow的时候在blockWhenExhausted为true时应用,-1的话则应用takeFirst办法,否则应用pollFirst(borrowMaxWaitDuration)办法

evict

getNumTests

org/apache/commons/pool2/impl/GenericObjectPool.java

    /**     * Calculates the number of objects to test in a run of the idle object     * evictor.     *     * @return The number of objects to test for validity     */    private int getNumTests() {        final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();        if (numTestsPerEvictionRun >= 0) {            return Math.min(numTestsPerEvictionRun, idleObjects.size());        }        return (int) (Math.ceil(idleObjects.size() /                Math.abs((double) numTestsPerEvictionRun)));    }
当numTestsPerEvictionRun为-1时,返回的是idleObjects.size()

EvictionConfig

org/apache/commons/pool2/impl/EvictionConfig.java

public class EvictionConfig {    private static final Duration MAX_DURATION = Duration.ofMillis(Long.MAX_VALUE);    private final Duration idleEvictDuration;    private final Duration idleSoftEvictDuration;    private final int minIdle;    /**     * Creates a new eviction configuration with the specified parameters.     * Instances are immutable.     *     * @param idleEvictDuration Expected to be provided by     *        {@link BaseGenericObjectPool#getMinEvictableIdleDuration()}     * @param idleSoftEvictDuration Expected to be provided by     *        {@link BaseGenericObjectPool#getSoftMinEvictableIdleDuration()}     * @param minIdle Expected to be provided by     *        {@link GenericObjectPool#getMinIdle()} or     *        {@link GenericKeyedObjectPool#getMinIdlePerKey()}     * @since 2.10.0     */    public EvictionConfig(final Duration idleEvictDuration, final Duration idleSoftEvictDuration, final int minIdle) {        this.idleEvictDuration = PoolImplUtils.isPositive(idleEvictDuration) ? idleEvictDuration : MAX_DURATION;        this.idleSoftEvictDuration = PoolImplUtils.isPositive(idleSoftEvictDuration) ? idleSoftEvictDuration : MAX_DURATION;        this.minIdle = minIdle;    }    //......}    
evict办法会结构EvictionConfig,minEvictableIdleDuration默认为30分钟;这里次要是针对正数进行了判断,正数则取的Long.MAX_VALUE;即softMinEvictableIdleDuration默认为-1,转换过去就是Long.MAX_VALUE
final EvictionConfig evictionConfig = new EvictionConfig(                        getMinEvictableIdleDuration(),                        getSoftMinEvictableIdleDuration(),                        getMinIdle());

DefaultEvictionPolicy

org/apache/commons/pool2/impl/DefaultEvictionPolicy.java

public class DefaultEvictionPolicy<T> implements EvictionPolicy<T> {    @Override    public boolean evict(final EvictionConfig config, final PooledObject<T> underTest, final int idleCount) {        // @formatter:off        return (config.getIdleSoftEvictDuration().compareTo(underTest.getIdleDuration()) < 0 &&                config.getMinIdle() < idleCount) ||                config.getIdleEvictDuration().compareTo(underTest.getIdleDuration()) < 0;        // @formatter:on    }}
DefaultEvictionPolicy的evict办法在idleCount大于minIdle且idleDuration大于idleSoftEvictDuration(默认为Long.MAX_VALUE)返回true,或者obj的idleDuration大于minEvictableIdleDuration(默认为30分钟)返回true

durationBetweenEvictionRuns

org/apache/commons/pool2/impl/BaseGenericObjectPool.java

    public final void setTimeBetweenEvictionRuns(final Duration timeBetweenEvictionRuns) {        this.durationBetweenEvictionRuns = PoolImplUtils.nonNull(timeBetweenEvictionRuns, BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS);        startEvictor(this.durationBetweenEvictionRuns);    }    final void startEvictor(final Duration delay) {        synchronized (evictionLock) {            final boolean isPositiverDelay = PoolImplUtils.isPositive(delay);            if (evictor == null) { // Starting evictor for the first time or after a cancel                if (isPositiverDelay) { // Starting new evictor                    evictor = new Evictor();                    EvictionTimer.schedule(evictor, delay, delay);                }            } else if (isPositiverDelay) { // Stop or restart of existing evictor: Restart                synchronized (EvictionTimer.class) { // Ensure no cancel can happen between cancel / schedule calls                    EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, true);                    evictor = null;                    evictionIterator = null;                    evictor = new Evictor();                    EvictionTimer.schedule(evictor, delay, delay);                }            } else { // Stopping evictor                EvictionTimer.cancel(evictor, evictorShutdownTimeoutDuration, false);            }        }    }
setTimeBetweenEvictionRuns办法会durationBetweenEvictionRuns(默认为-1)去startEvictor;当改值为正数时则执行EvictionTimer.cancel,即不启动evictor线程

cancel

org/apache/commons/pool2/impl/EvictionTimer.java

    /**     * Removes the specified eviction task from the timer.     *     * @param evictor   Task to be cancelled.     * @param timeout   If the associated executor is no longer required, how     *                  long should this thread wait for the executor to     *                  terminate?     * @param restarting The state of the evictor.     */    static synchronized void cancel(final BaseGenericObjectPool<?>.Evictor evictor, final Duration timeout,            final boolean restarting) {        if (evictor != null) {            evictor.cancel();            remove(evictor);        }        if (!restarting && executor != null && taskMap.isEmpty()) {            executor.shutdown();            try {                executor.awaitTermination(timeout.toMillis(), TimeUnit.MILLISECONDS);            } catch (final InterruptedException e) {                // Swallow                // Significant API changes would be required to propagate this            }            executor.setCorePoolSize(0);            executor = null;        }    }
evictorShutdownTimeoutDuration即executor.awaitTermination的timeout参数

小结

参数类别参数值jedisConfig值commons-pool默认值解释
根本lifotruetrue后进先出
根本fairnessfalsefalse非偏心机制
数量maxTotal8-最大连接数
数量maxIdle8-最大空间连接数
数量minIdle0-起码闲暇连接数
阻塞获取blockWhenExhaustedtruetrue连接池耗尽时,获取连贯是否阻塞期待
阻塞获取maxWaitMillis-1-1blockWhenExhausted为true时阻塞期待多久
衰弱检测testOnCreatefaslefasle创立连贯的时候检测
衰弱检测testOnBorrowfalsefalse借用连贯的时候检测
衰弱检测testOnReturnfalsefalse偿还连贯的时候检测
衰弱检测testWhileIdletruefalse在闲暇连贯检测时检测
evictdurationBetweenEvictionRuns30秒-1evictor线程运行距离,-1为不运行
evictminEvictableIdleDuration60秒30分钟连贯闲暇的最小工夫
evictsoftMinEvictableIdleDuration-1-1-1即Long.MAX_VALUE,它与idleCount>minIdle条件一起思考
evictnumTestsPerEvictionRun-13每次闲暇连贯回收器线程(如果有)运行时查看的连贯数量, -1示意全副
evictevictionPolicyClassNameDefaultEvictionPolicyDefaultEvictionPolicy判断是否须要evict的PolicyClass
evictevictorShutdownTimeoutDuration10s10s敞开evictor线程池的等待时间
jmxjmxEnabledtruetrue是否开启jmx
jmxjmxNamePrefixpoolpooljmx名称前缀
jmxjmxNameBasenullnullnull示意由pool本人定义jmxNameBase

JedisConfig默认帮咱们配置了testWhileIdle为true(默认为false),minEvictableIdleTime为60s(默认为30分钟),timeBetweenEvictionRuns为30s(默认为-1),numTestsPerEvictionRun为-1(即检测所有闲暇连贯,默认值为3),利用evictor线程来检测闲暇连贯的衰弱状况

另外由聊聊jedis的return行为这篇剖析能够得悉在执行命令时若redis出问题,Jedis自身会标记底层connection为broken,在finally偿还时会destory连贯,保障连接池连贯最终都会被清空重建。

另外在并发量比拟大的场景,若要保障连接池的稳固数量则能够把minIdle设置成与maxTotal和maxIdle一样即可;若不想因为idle工夫被频繁destory则能够设置minEvictableIdleTime为-1,evict办法始终返回false,evictor线程始终走的是testWhileIdle的逻辑;maxWaitMillis要设置一个正当值防止连接池耗尽阻塞线程,或者间接设置blockWhenExhausted为false

doc

  • GenericObjectPool参数解析
  • JedisPool资源池优化
  • 一次拜访Redis延时高问题排查与总结
  • 实战总结|一次拜访Redis延时高问题排查与总结(续)