Redis 客户端之 Jedis ——JedisPool 分析

Jedis

jedis 是 redis 官方推荐的 java 客户端,目前稳定的版本是 2.9.0

JedisPool

jedisPool 是 Jedis 内部管理到 redis 的连接资源,内部的实例是 Jedis,通过连接池策略来优化对 redis 的访问。

JedisPoolConfig

JedisPoolConfig是创建 JedisPool的配置类,继承自 ApacheGenericObjectPoolConfig
GenericObjectPoolConfig 类各参数默认值和意义:

blockWhenExhausted 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true

evictionPolicyClassName 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)

lifo 是否启用后进先出, 默认true 

maxTotal 最大连接数, 默认8个(连接池能创建的最大连接数量)

maxIdle 最大空闲连接数, 默认8个(在连接 return 到 连接池时,如果空闲连接数 == maxIdle 则直接关闭连接,一般建议该值和 maxTotal 相等)

minIdle最小空闲连接数, 默认0 (该参数会保证 连接池 中在没有达到 maxTotal 时,一直会保持 minIdle 的空闲连接数,但是定时任务是否启动,由下一个参数决定) 

maxWaitMillis 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1

timeBetweenEvictionRunsMillis 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1 
 
minEvictableIdleTimeMillis 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)

numTestsPerEvictionRun 每次逐出检查时 逐出的最大数目 如果为负数就是 : idle.size()/abs(n), 默认3

softMinEvictableIdleTimeMillis 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)

testOnBorrow 在获取连接的时候检查有效性, 默认false

testWhileIdle 在空闲时检查有效性, 默认false

testOnCreate 在创建连接时检查有效性, 默认 false

testOnReturn 在返回连接时检查有效性, 默认 false

JedisPoolConfig类如下:

public class JedisPoolConfig extends GenericObjectPoolConfig {
 	 public JedisPoolConfig() {
    // defaults to make your life with connection pool easier :)
    setTestWhileIdle(true);
    setMinEvictableIdleTimeMillis(60000);
    setTimeBetweenEvictionRunsMillis(30000);
    setNumTestsPerEvictionRun(-1);
  }
}

不同点

  • JedisPoolConfig设置 testWhileIdletrue,此参数设置定时任务检查空闲连接,具体的定时任务由下面的参数配置
  • minEvictableIdleTimeMillis=60000表示连接空闲 1 分钟,则直接关闭
  • timeBetweenEvictionRunsMillis=30000表示定时任务间隔30s执行一次,小于 0 时则不执行
  • numTestsPerEvictionRun=-1表示每次逐出的空闲连接数量,为负数时 idle.size()/abs(n)

JedisPool检查策略

如何** JedisPool evict schedule

JedisPool内部实际持有的是 ApacheGenericObjectPool,所有实际的操作都有 GenericObjectPool实现,我们直接撸代码,下图中红色方框标出的定时任务的入口
Redis 客户端之 Jedis ——JedisPool 分析

timeBetweenEvictionRunsMillis这个参数会控制 Evictor是否启动,当小于 0 时,定时任务不启动,JedisPoolConfig默认值30000ms, GenericsObjectPoolConfig默认值是 -1
Redis 客户端之 Jedis ——JedisPool 分析

Evictor Timer 的作用

Evictor extends TimerTask,具体的实现如下:

  1. 首先执行 evict()方法
  2. 然后在执行 ensureMinIdle()方法
    Redis 客户端之 Jedis ——JedisPool 分析

接下来,我们看下evict()方法内部到底干了些什么

  1. 先判断idle的阻塞队列中是否有空闲连接

  2. 然后直接根据我们设置的参数创建 EvictionConfig对象

  3. for 循环来处理空闲的连接
    Redis 客户端之 Jedis ——JedisPool 分析

  4. 执行 evict(config, underTest, idleCount)方法来判断是否逐出连接,如果不逐出,同时 testOnIldetrue时,则检查连接的有效性,不有效则 destroy该连接,会从 idle的队列中移除,具体的关闭方法则不看了
    Redis 客户端之 Jedis ——JedisPool 分析

    具体的判断关闭连接的方法我们来看下,有两个条件

    1. 一个是 空闲时间超过最小空闲时间,则直接关闭
    2. 另一个是共享的连接数大于 我们设置的最小空闲连接,同时该连接的空闲时间要大于 softMinEvictableIdleTimeMillis,该值的默认值是 -1,所以该条件只需要判断 空闲 连接是否大于我们设置的 minIdle
      Redis 客户端之 Jedis ——JedisPool 分析
  5. 让我们看下 ensureMinIdle()的真容吧

    该方法内部调用的是一个重载的方法,传入的参数是我们设置的 minIdletrue
    Redis 客户端之 Jedis ——JedisPool 分析
    如果最小空闲连接小于1 或者 连接池关闭 则直接返回,
    否则会进入到一个 while 循环,当空闲连接小于我们设置的 minIdle 时,则会创建新连接并添加到 idleObjects队列中,直到空闲连接 >= minIdle,或者创建连接失败
    Redis 客户端之 Jedis ——JedisPool 分析
    注意

    1. 使用 GenericObjectPoolConfig 该配置类时,需要自己设置启动的检查参数,不然 minIdle 和 maxIdle 都无效,同时建立的所有连接都不会关闭
    2. 该空闲检查任务总是会先关闭达到空闲条件的连接,同时创建新连接直到达到最小空闲连接数

maxIdle 的用处

returnObject的方法中,首先会判断该连接的状态是否是被分配的,如果状态异常则抛出异常,否则执行 markReturning()方法,该方法只是把该连接的状态标记为 return

如果 testOnReturnture则会 validateObject()来验证连接是否是健康的,不健康则调 destroy方法销毁,同时会保证连接池中至少有 1个空闲连接

passivateObject()这个方法内部没有实现
Redis 客户端之 Jedis ——JedisPool 分析
接下来才是真正的放回 idleObjects空闲队列, 先会判断 idleObjects队列中的空闲连接数量是否大于 maxIdle, 大于时则直接关闭连接,否则添加回等待队列
Redis 客户端之 Jedis ——JedisPool 分析