点击上方☝Java编程技术乐园,轻松关注!及时获取有趣有料的技术文章
![b4a9466e8fad566ad3ad81f5382d7fef.png](https://i-blog.csdnimg.cn/blog_migrate/2e7aba3f04188a7b287c9a206619b9d6.jpeg)
做一个积极的人
编码、改bug、提升自己
我有一个乐园,面向编程,春暖花开!
你好,JedisPoolConfig
Java中使用Jedis作为连接Redis的工具。在使用Jedis的也可以配置JedisPool连接池,JedisPool配置参数大部分是由JedisPoolConfig的对应项来赋值的。本文简单总结几个常用的配置,然后通过源码(版本jedis-3.1.0)的角度让你理解配置这些参数的原理。
首先了解一下池化((对象池、数据库连接池、线程池等等))的一些思想和好处。方便后面对JedisPoolConfig的配置的理解。
池化的基本思想:
1、可以在初始化的时候创建一些对象,当有需要使用的时候不直接从池中获取,提高响应速度;
2、使用过的对象不进行销毁,保存起来,等下一次需要对象的时候,拿出来重复使用,减少频繁创建对象所造成的开销;
3、创建的对象统一保存,方面管理和维护。
池化好处总结:
1、提高响应的速度
2、降低资源的消耗
3、方便管理和维护
JedisPoolConfig配置说明
类图和源码解析
首先看一下类图:
![84bb554dfdbb2870827842ba42fa2426.png](https://i-blog.csdnimg.cn/blog_migrate/aad11483344ac9ede9fc32aeb8d50c56.jpeg)
- BaseGenericObjectPool:封装公共的配置的参数。
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS; // DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L private long minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; // DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L private long timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; // DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3 private int numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; // DEFAULT_TEST_ON_CREATE = false private boolean testOnCreate = DEFAULT_TEST_ON_CREATE; // DEFAULT_TEST_ON_BORROW = false private boolean testOnBorrow = DEFAULT_TEST_ON_BORROW; // DEFAULT_TEST_ON_RETURN = false private boolean testOnReturn = DEFAULT_TEST_ON_RETURN; // DEFAULT_TEST_WHILE_IDLE = false private boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE; //...}
- GenericObjectPoolConfig:继承BaseGenericObjectPool,内部代码很简单,封装了GenericObjectPool的配置。主要是maxTotal、maxIdle、minIdle。 此类不是线程安全的;它仅用于提供创建池时使用的属性。在创建单例的JedisPool 使用JedisPoolConfig需要注意线程安全问题,下面会有个demo介绍创建单例JedisPool。
public class GenericObjectPoolConfig extends BaseObjectPoolConfig { /** * The default value for the {@code maxTotal} configuration attribute. * @see GenericObjectPool#getMaxTotal() */ public static final int DEFAULT_MAX_TOTAL = 8; // ... // DEFAULT_MAX_TOTAL = 8 private int maxTotal = DEFAULT_MAX_TOTAL; // DEFAULT_MAX_IDLE = 8 private int maxIdle = DEFAULT_MAX_IDLE; // DEFAULT_MIN_IDLE = 0 private int minIdle = DEFAULT_MIN_IDLE; // ...}
- JedisPoolConfig继承了上面的优良基因,然后又对其他的几个设置属性重新设值。
为了方便使用,Jedis提供了JedisPoolConfig,它继承了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); }}
配置参数解析
JedisPoolConfig中可以能够配置的参数有很多,连接池实现依赖apache 的commons-pool2。上面源码也大致列举了一些配置参数,下面在详细说明一下。
把池理解为工厂,池中的实例理解为工人,如下图,这样池中的很多参数理解起来就比较容易了。
![c2144bf877d5a1f29f70b39acdae01b5.png](https://i-blog.csdnimg.cn/blog_migrate/2208423d5702c46a4fa7bffbb2967120.jpeg)
Jedis连接就是连接池中JedisPool管理的资源,JedisPool保证资源在一个可控范围内,并且保障线程安全。使用合理的GenericObjectPoolConfig配置能够提升Redis的服务性能,降低资源开销。下列两表将对一些重要参数进行说明,并提供设置建议。
![e77066682f05e2f91d31f448dadf6b5d.png](https://i-blog.csdnimg.cn/blog_migrate/708dd2cc5032441cf2a854b898ba1f2d.jpeg)
空闲Jedis对象检测由下列四个参数组合完成,testWhileIdle是该功能的开关。
![447e029b596b34df56c1f81a54e3d68b.png](https://i-blog.csdnimg.cn/blog_migrate/a35158645b8fa811ef04592a5797734f.jpeg)
说明 可以在org.apache.commons.pool2.impl.BaseObjectPoolConfig中查看全部默认值。
关键参数设置建议
maxTotal(最大连接数)
想合理设置maxTotal(最大连接数)需要考虑的因素较多,如:
- 业务希望的Redis并发量;
- 客户端执行命令时间;
- Redis资源,例如nodes (如应用个数等) * maxTotal不能超过Redis的最大连接数;
- 资源开销,例如虽然希望控制空闲连接,但又不希望因为连接池中频繁地释放和创建连接造成不必要的开销。
假设一次命令时间,即borrow|return resource加上Jedis执行命令 ( 含网络耗时)的平均耗时约为1ms,一个连接的QPS大约是1000,业务期望的QPS是50000,那么理论上需要的资源池大小是50000 / 1000 = 50。
但事实上这只是个理论值,除此之外还要预留一些资源,所以maxTotal可以比理论值大一些。这个值不是越大越好,一方面连接太多会占用客户端和服务端资源,另一方面对于Redis这种高QPS的服务器,如果出现大命令的阻塞,即使设置再大的资源池也无济于事。
maxIdle与minIdle
maxIdle实际上才是业务需要的最大连接数,maxTotal 是为了给出余量,所以 maxIdle 不要设置得过小,否则会有new Jedis(新连接)开销,而minIdle是为了控制空闲资源检测。
连接池的最佳性能是maxTotal=maxIdle,这样就避免了连接池伸缩带来的性能干扰。但如果并发量不大或者maxTotal设置过高,则会导致不必要的连接资源浪费。
您可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。
使用监控获取合理值
在实际环境中,比较可靠的方法是通过监控来尝试获取参数的最佳值。可以考虑通过JMX等方式实现监控,从而找到合理值。
上面参数配置:JedisPool资源池优化
创建JedisPool代码
// volatile 修饰private static volatile JedisPool jedisPool = null;private JedisPoolUtils(){}public static JedisPool getJedisPoolInstance() { // 使用双重检查创建单例 if(null == jedisPool) { synchronized (JedisPoolUtils.class) { if(null == jedisPool) { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(10); poolConfig.setMaxIdle(10); poolConfig.setMinIdle(2); poolConfig.setMaxWaitMillis(30*1000); poolConfig.setTestOnBorrow(true); poolConfig.setTestOnReturn(true); poolConfig.setTimeBetweenEvictionRunsMillis(10*1000); poolConfig.setMinEvictableIdleTimeMillis(30*1000); poolConfig.setNumTestsPerEvictionRun(-1); jedisPool = new JedisPool(poolConfig,"localhost