掌握JedisPoolConfig参数配置,学会调优技能
点击上方☝Java编程技术乐园,轻松关注!
及时获取有趣有料的技术文章
做一个积极的人
编码、改bug、提升自己
我有一个乐园,面向编程,春暖花开!
你好,JedisPoolConfig
Java中使用Jedis
作为连接Redis
的工具。在使用Jedis
的也可以配置JedisPool
连接池,JedisPool
配置参数大部分是由JedisPoolConfig
的对应项来赋值的。本文简单总结几个常用的配置,然后通过源码(版本jedis-3.1.0
)的角度让你理解配置这些参数的原理。
首先了解一下池化((对象池、数据库连接池、线程池等等))的一些思想和好处。方便后面对JedisPoolConfig
的配置的理解。
池化的基本思想:
1、可以在初始化的时候创建一些对象,当有需要使用的时候不直接从池中获取,提高响应速度;
2、使用过的对象不进行销毁,保存起来,等下一次需要对象的时候,拿出来重复使用,减少频繁创建对象所造成的开销;
3、创建的对象统一保存,方面管理和维护。
池化好处总结:
1、提高响应的速度
2、降低资源的消耗
3、方便管理和维护
JedisPoolConfig
配置说明
类图和源码解析
首先看一下类图:
•BaseGenericObjectPool
:封装公共的配置的参数。
private long maxWaitMillis = DEFAULT_MAX_WAIT_MILLIS;// DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30Lprivate long minEvictableIdleTimeMillis =DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;// DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1Lprivate long timeBetweenEvictionRunsMillis =DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;// DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3private int numTestsPerEvictionRun =DEFAULT_NUM_TESTS_PER_EVICTION_RUN;// DEFAULT_TEST_ON_CREATE = falseprivate boolean testOnCreate = DEFAULT_TEST_ON_CREATE;// DEFAULT_TEST_ON_BORROW = falseprivate boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;// DEFAULT_TEST_ON_RETURN = falseprivate boolean testOnReturn = DEFAULT_TEST_ON_RETURN;// DEFAULT_TEST_WHILE_IDLE = falseprivate boolean testWhileIdle = DEFAULT_TEST_WHILE_IDLE;//...
}
•GenericObjectPoolConfig
:继承BaseGenericObjectPool
,内部代码很简单,封装了GenericObjectPool
的配置。主要是maxTotal
、maxIdle
、minIdle
。 此类不是线程安全的;它仅用于提供创建池时使用的属性。在创建单例的JedisPool
使用JedisPoolConfig
需要注意线程安全问题,下面会有个demo介绍创建单例JedisPool
。
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;// ...// DEFAULT_MAX_TOTAL = 8private int maxTotal = DEFAULT_MAX_TOTAL;// DEFAULT_MAX_IDLE = 8private int maxIdle = DEFAULT_MAX_IDLE;// DEFAULT_MIN_IDLE = 0private 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
。上面源码也大致列举了一些配置参数,下面在详细说明一下。
把池理解为工厂,池中的实例理解为工人,如下图,这样池中的很多参数理解起来就比较容易了。
Jedis连接就是连接池中JedisPool管理的资源,JedisPool保证资源在一个可控范围内,并且保障线程安全。使用合理的GenericObjectPoolConfig配置能够提升Redis的服务性能,降低资源开销。下列两表将对一些重要参数进行说明,并提供设置建议。
参数 | 说明 | 默认值 | 建议 |
maxTotal | 资源池中的最大连接数 | 8 | 参见关键参数设置建议 |
maxIdle | 资源池允许的最大空闲连接数 | 8 | 参见关键参数设置建议 |
minIdle | 资源池确保的最少空闲连接数 | 0 | 参见关键参数设置建议 |
blockWhenExhausted | 当资源池用尽后,调用者是否要等待。只有当值为true时,下面的maxWaitMillis才会生效。 | true | 建议使用默认值。 |
maxWaitMillis | 当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)。 | -1(表示永不超时) | 不建议使用默认值。 |
testOnBorrow | 向资源池借用连接时是否做连接有效性检测(ping)。检测到的无效连接将会被移除。 | false | 业务量很大时候建议设置为false,减少一次ping的开销。 |
testOnReturn | 向资源池归还连接时是否做连接有效性检测(ping)。检测到无效连接将会被移除。 | false | 业务量很大时候建议设置为false,减少一次ping的开销。 |
jmxEnabled | 是否开启JMX监控 | true | 建议开启,请注意应用本身也需要开启。 |
空闲Jedis对象检测由下列四个参数组合完成,testWhileIdle是该功能的开关。
名称 | 说明 | 默认值 | 建议 |
testWhileIdle | 是否开启空闲资源检测。 | false | true |
timeBetweenEvictionRunsMillis | 空闲资源的检测周期(单位为毫秒) | -1(不检测) | 建议设置,周期自行选择,也可以默认也可以使用下方JedisPoolConfig 中的配置。 |
minEvictableIdleTimeMillis | 资源池中资源的最小空闲时间(单位为毫秒),达到此值后空闲资源将被移除。 | 180000(即30分钟) | 可根据自身业务决定,一般默认值即可,也可以考虑使用下方JeidsPoolConfig中的配置。 |
numTestsPerEvictionRun | 做空闲资源检测时,每次检测资源的个数。 | 3 | 可根据自身应用连接数进行微调,如果设置为 -1,就是对所有连接做空闲监测。 |
说明 可以在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资源池优化[1]
创建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",6379);}}}return jedisPool;
}
实例创建和释放大致流程解析
根据流程进行源码解析
创建过程
使用pool.getResource()
进行Jedis实例的创建。
//org.apache.commons.pool2.impl.GenericObjectPool#borrowObject(long)
public T borrowObject(final long borrowMaxWaitMillis) throws Exception {final boolean blockWhenExhausted = getBlockWhenExhausted();PooledObject<T> p = null;boolean create;final long waitTime = System.currentTimeMillis();while (p == null) {create = false;// 从空闲队列中获取p = idleObjects.pollFirst();if (p == null) {// 创建实例p = create();if (p != null) {create = true;}}// 吃资源是否耗尽if (blockWhenExhausted) {if (p == null) {// 等待时间小于0if (borrowMaxWaitMillis < 0) {p = idleObjects.takeFirst();} else {p = idleObjects.pollFirst(borrowMaxWaitMillis,TimeUnit.MILLISECONDS);}}if (p == null) {throw new NoSuchElementException("Timeout waiting for idle object");}} else {if (p == null) {throw new NoSuchElementException("Pool exhausted");}}if (!p.allocate()) {p = null;}if (p != null) {try {// 重新初始化要由池返回的实例。factory.activateObject(p);} catch (final Exception e) {}}}updateStatsBorrow(p, System.currentTimeMillis() - waitTime);return p.getObject();
}
释放过程
从Jedis3.0版本后pool.returnResource()
遭弃用,官方重写了Jedis的close方法用以代替;官方建议应用redis.clients.jedis#Jedis的close方法进行资源回收,官方代码如下:
@Overridepublic void close() {if (dataSource != null) {JedisPoolAbstract pool = this.dataSource;this.dataSource = null;if (client.isBroken()) {pool.returnBrokenResource(this);} else {pool.returnResource(this);}} else {super.close();}}
这里主要看:pool.returnResource(this);
//org.apache.commons.pool2.impl.GenericObjectPool#returnObject
public void returnObject(final T obj) {// 获取要释放的实例对象final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));if (p == null) {if (!isAbandonedConfig()) {throw new IllegalStateException("Returned object not currently part of this pool");}return; // Object was abandoned and removed}// 将对象标记为返回池的状态。markReturningState(p);final long activeTime = p.getActiveTimeMillis();// 这里就和上面配置的参数有关系,释放的时候是否做连接有效性检测(ping)if (getTestOnReturn() && !factory.validateObject(p)) {try {destroy(p);} catch (final Exception e) {swallowException(e);}try {ensureIdle(1, false);} catch (final Exception e) {swallowException(e);}updateStatsReturn(activeTime);return;}// 检查空闲对象,如果最大空闲对象数小于当前idleObjects大小,则销毁final int maxIdleSave = getMaxIdle();if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {try {destroy(p);} catch (final Exception e) {swallowException(e);}} else {// 否则加入到空闲队列中,空闲队列是一个双端队列// getLifo 也和配置的参数有关,默认Trueif (getLifo()) {// last in first out,加到队头idleObjects.addFirst(p);} else {// first in first out ,加到队尾idleObjects.addLast(p);}}updateStatsReturn(activeTime);
}
上面创建和释放删除了一些代码,具体完整代码都是在GenericObjectPool
类中。
小结,后悔有期
看完本文,应该大致对JedisPoolConfig
有了一定的了解,指定里面的一些配置参数,并且能够基本的参数调优,以及实例资源的创建和释放的过程。
如果感谢兴趣的伙伴可以下载Jedis的源码进行阅读和学习,掌握了JedisPoolConfig
的配置,其他池化框架的配置也是大同小异,举一反三!江湖不远,后会有期!
References
[1]
JedisPool资源池优化: https://www.alibabacloud.com/help/zh/doc-detail/98726.htm
推荐阅读:
Redis的模糊查询在生产环境出现严重的性能问题
避免产生事故,应如何访问 redis 中的海量数据?
欢迎长按下图关注公众号
后台回复【秘籍】,获取珍藏的武功秘籍!
一起来修炼
黯然~销魂
掌握JedisPoolConfig参数配置,学会调优技能相关推荐
- 在RedHat Enterprise Linux 上Oracle 9i的安装配置与调优
1 安装配置Oracle 9i数据库 本章描述内容如下所示: 1.1 安装前的准备工作 介绍在安装Oracle之前所需的准备工作. 1.2安装前的系统设置 介绍在安装Oracle之前所必须的系统设置. ...
- Nginx安装/负载均衡/反向代理配置与调优
[Nginx安装] Linux下直接使用包管理安装 sudo apt-get install nginx 使用whereis命令查看安装位置 whereis nginx #sbin下代表nginx可执 ...
- SpringBoot中Web容器配置和调优
SpringBoot的启动容器主要是Tomcat,Jetty,Undertow三种容器类型,具体的配置类为 org.springframework.boot.autoconfigure.web.Ser ...
- Java启动参数与内存调优一些学习笔记
转载自 Java启动参数与内存调优一些学习笔记 .参数的含义 -Xms128m JVM初始分配的堆内存 -Xmx512m JVM最大允许分配的堆内存,按需分配 -XX:PermSize=64M JV ...
- R语言使用caret包的train函数构建xgboost模型(基于linear算法)模型构建分类模型、trainControl函数设置交叉验证参数、自定义调优评估指标
R语言使用caret包的train函数构建xgboost模型(基于linear算法)模型构建分类模型.trainControl函数设置交叉验证参数.自定义调优评估指标.tuneLength参数和tun ...
- R语言使用caret包的train函数构建xgboost模型(基于gbtree算法)模型构建分类模型、trainControl函数设置交叉验证参数、自定义调优评估指标
R语言使用caret包的train函数构建xgboost模型(基于gbtree算法)模型构建分类模型.trainControl函数设置交叉验证参数.自定义调优评估指标.tuneLength参数和tun ...
- R语言使用caret包的train函数构建多项式核SVM模型(多项式核函数)模型构建分类模型、trainControl函数设置交叉验证参数、自定义调优评估指标
R语言使用caret包的train函数构建多项式核SVM模型(多项式核函数)模型构建分类模型.trainControl函数设置交叉验证参数.自定义调优评估指标.tuneLength参数和tuneGri ...
- R语言使用caret包的train函数构建xgboost模型(基于dart算法)模型构建分类模型、trainControl函数设置交叉验证参数、自定义调优评估指标
R语言使用caret包的train函数构建xgboost模型(基于dart算法)模型构建分类模型.trainControl函数设置交叉验证参数.自定义调优评估指标.tuneLength参数和tuneG ...
- R语言使用caret包的train函数构建惩罚判别分析模型(pda)构建分类模型、trainControl函数设置交叉验证参数、自定义调优评估指标
R语言使用caret包的train函数构建惩罚判别分析模型(pda)构建分类模型.trainControl函数设置交叉验证参数.自定义调优评估指标.tuneLength参数和tuneGrid参数超参数 ...
最新文章
- 网文作者:我太监了;GPT-3:我给你接上
- python怎么安装包-Python-如何离线安装软件包?
- Android Studio 提示与技巧(官方文档翻译)
- 白话Elasticsearch08-深度探秘搜索技术之基于boost的细粒度搜索条件权重控制
- ctf.show-萌新计划(1-7)
- 计算机类和鼠标类是什么关系,电脑自己关机和鼠标键盘有关系吗
- java中使用几率_Java中使用蒙特卡洛算法计算德州扑克成牌概率(二)- 计算牌面分值...
- 努力≠上进!那些“熬夜”持续精进的人有多可怕!
- vmware虚拟机磁盘挂载
- 四旋翼无人机飞控系统设计(方案篇)
- MapWinGis学习(一) 新建图层 在指定点上打上图标
- 记录某大门户网站自动跳转不良网站,团队通宵排查病毒木马全过程
- H3C 802.11n的频宽模式
- abaqus的python安装文件在哪_拓展abaqus python 模块
- 如何快速提高WiFi速度:1个小技巧提升2.5倍
- 中国艺术孙溟㠭篆刻作品《零落成泥碾作尘,只有香如故》
- 中海达ihand30手簿使用说明_中海达iHand30 手簿使用说明书
- mac usb iso linux系统安装教程,Mac上制作linux系统U盘安装盘
- 【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
- e的x次方在python中怎么打出来_#e的x次方在excel里面怎么打出来#excel中10的几次方怎么输入...
热门文章
- 深入了解arduino舵机控制库文件Servo.h
- android视频播放器设置圆角,Android设置上圆角和下圆角
- 最新副本祖尔格拉布完全攻略(必修课)
- 微信发送的视频有限制
- c语言 高斯日记,高斯日记 – 蓝桥杯
- python使用@contextmanager来定义上下文管理器(一篇文章,彻底明白!码文并茂,简单明了)和 yield 和 __enter__ 和 __exit__
- elementUI中,操作表格单行的dom-锁定和解锁——$nextTick用法-dom根据数据改变而改变
- 中国喷管装置市场趋势报告、技术动态创新及市场预测
- 陋室快报 | 近期好文分享-20211127
- 34.写一个排序算法1-100随机数字进行排序