1. Jedis是什么?
官网
Jedis 是官方推荐的java客户端!SpringBoot的RedisTemplate的底层也是Jedis;
2. 为什么使用池化?
-
背景:
- Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。
- Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。
-
解决方法:
- 客户端角度:为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized;
- 服务器角度:利用setnx实现锁;
-
选择池化的好处:
- 一个对象在其生命周期大致可分为 “创建”, “使用”, “销毁” 三大阶段, 那么它的总时间就是T1(创建)+T2(使用)+T3(销毁), 如果创建N个对象都需要这样的步骤的话是非常耗性能的,就算JVM对垃圾回收机制有优化,但"创建"和"销毁"多少总会占用部分资源;
-
使用池化的好处:
- 减少 T1(创建)+T3(销毁) 所消耗的资源;
3. 如何使用池化?
JedisPool是redis 客户端jedis 的连接池,内部池对象的管理就是采用commons -pool2。采用它的有很多优点是,例如:避免过多的创建连对象、自动处理最大空闲数量,避免自己处理线程问题等等;
3.1 commons-pool2 是什么?
commons-pool2是Apache下一个开源的公共资源池;commons-pool官网 commons-pool 相关Api
3.2 commons-pool2 怎么使用?
-
核心组件:
-
PooledObject(池对象)
用于封装对象(如:线程、数据库连接、TCP连接),将其包裹成可被池管理的对象。提供了两个默认的池对象实现: -
DefaultPoolObject:用于非软引用的普通对象。
-
PooledSoftReference:用于软引用的对象。
-
-
PooledObjectFactory(池对象工厂)
定义了操作PooledObject实例生命周期的一些方法,PooledObjectFactory必须实现线程安全。已经有两个抽象工厂:- BasePooledObjectFactory。
- BaseKeyedPooledObjectFactory。
-
Object Pool (对象池)
Object Pool负责管理PooledObject,如:借出对象,返回对象,校验对象,有多少激活对象,有多少空闲对象。有三个默认的实现类:- GenericObjectPool。
- ProsiedObjectPool。
- SoftReferenceObjectPool
- BorrowObject (借出对象)
- ReturnObject (返还对象)
3.3 demo
- 创建实例对象
package wang.pool;
/**
* 测试
*
* @author wql
* @date 2022/12/6 13:28
*/
public class TestWang {
public TestWang(){}
public void study(){
System.out.println(" day day up !");
}
}
- 创建工厂
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
/**
* 测试对象 工厂
*
* @author wql
* @date 2022/12/6 13:32
*/
public class TestWangFactory implements PooledObjectFactory<TestWang> {
/**
* 生产
* <p>
* 这个方法用于产生新的对象
*/
@Override
public PooledObject<TestWang> makeObject() throws Exception {
return new DefaultPooledObject<TestWang>(new TestWang());
}
/**
* 销毁
* <p>
* 这个方法用于销毁被validateObject判定为已失效的对象
*/
@Override
public void destroyObject(PooledObject<TestWang> pooledObject) throws Exception {
}
/**
* 校验
* <p>
* 这个方法用于校验一个具体的对象是否仍然有效,已失效的对象会被自动交给destroyObject方法销毁。
*/
@Override
public boolean validateObject(PooledObject<TestWang> pooledObject) {
return false;
}
/**
* 激活
* <p>
* 设置为适合开始使用的状态
*/
@Override
public void activateObject(PooledObject<TestWang> pooledObject) throws Exception {
}
/**
* 挂起
* <p>
* 这个方法用于将对象“挂起”——设置为适合开始休眠的状态
*/
@Override
public void passivateObject(PooledObject<TestWang> pooledObject) throws Exception {
}
}
- 创建池
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
/**
* 测试对象 池
*
* @author wql
* @date 2022/12/6 13:36
*/
public class TestWangPool {
private GenericObjectPool<TestWang> pool;
public TestWangPool() {
pool = new GenericObjectPool<TestWang>(new TestWangFactory(), new GenericObjectPoolConfig<TestWang>());
}
public TestWang getTestWang() {
try {
return pool.borrowObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void returnTestWang(TestWang testWang) {
pool.returnObject(testWang);
}
}
- 测试
package wang.pool;
/**
* @author wql
* @date 2022/12/6 9:42
*/
public class TestMain {
public static void main(String[] args) {
TestWangPool testWangPool = new TestWangPool();
TestWang testWang = testWangPool.getTestWang();
testWang.study();
testWangPool.returnTestWang(testWang);
}
}
3.4 Jedis是如何使用common-pool2 实践的?
3.5 JedisPool参数说明
3.5.1 BaseObjectPoolConfig:封装公共的配置的参数
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.apache.commons.pool2.impl;
import org.apache.commons.pool2.BaseObject;
public abstract class BaseObjectPoolConfig<T> extends BaseObject implements Cloneable {
public static final boolean DEFAULT_LIFO = true;
public static final boolean DEFAULT_FAIRNESS = false;
public static final long DEFAULT_MAX_WAIT_MILLIS = -1L;
public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1800000L;
public static final long DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS = -1L;
public static final long DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS = 10000L;
public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
public static final boolean DEFAULT_TEST_ON_CREATE = false;
public static final boolean DEFAULT_TEST_ON_BORROW = false;
public static final boolean DEFAULT_TEST_ON_RETURN = false;
public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
public static final boolean DEFAULT_BLOCK_WHEN_EXHAUSTED = true;
public static final boolean DEFAULT_JMX_ENABLE = true;
public static final String DEFAULT_JMX_NAME_PREFIX = "pool";
public static final String DEFAULT_JMX_NAME_BASE = null;
public static final String DEFAULT_EVICTION_POLICY_CLASS_NAME = DefaultEvictionPolicy.class.getName();
private boolean lifo = true;
private boolean fairness = false;
private long maxWaitMillis = -1L;
private long minEvictableIdleTimeMillis = 1800000L;
private long evictorShutdownTimeoutMillis = 10000L;
private long softMinEvictableIdleTimeMillis = -1L;
private int numTestsPerEvictionRun = 3;
private EvictionPolicy<T> evictionPolicy = null;
private String evictionPolicyClassName;
private boolean testOnCreate;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean testWhileIdle;
private long timeBetweenEvictionRunsMillis;
private boolean blockWhenExhausted;
private boolean jmxEnabled;
private String jmxNamePrefix;
private String jmxNameBase;
public BaseObjectPoolConfig() {
this.evictionPolicyClassName = DEFAULT_EVICTION_POLICY_CLASS_NAME;
this.testOnCreate = false;
this.testOnBorrow = false;
this.testOnReturn = false;
this.testWhileIdle = false;
this.timeBetweenEvictionRunsMillis = -1L;
this.blockWhenExhausted = true;
this.jmxEnabled = true;
this.jmxNamePrefix = "pool";
this.jmxNameBase = DEFAULT_JMX_NAME_BASE;
}
....
}
3.5.2 GenericObjectPoolConfig:
继承BaseGenericObjectPool,封装了GenericObjectPool的配置。 此类不是线程安全的;它仅用于提供创建池时使用的属性。在创建单例的JedisPool 使用
public class GenericObjectPoolConfig<T> extends BaseObjectPoolConfig<T> {
public static final int DEFAULT_MAX_TOTAL = 8;
public static final int DEFAULT_MAX_IDLE = 8;
public static final int DEFAULT_MIN_IDLE = 0;
private int maxTotal = 8;
private int maxIdle = 8;
private int minIdle = 0;
}
3.5.3 JedisPoolConfig:
它继承了GenericObjectPoolConfig在空闲检测上的一些设置
public class JedisPoolConfig extends GenericObjectPoolConfig {
public JedisPoolConfig() {
this.setTestWhileIdle(true);
this.setMinEvictableIdleTimeMillis(60000L);
this.setTimeBetweenEvictionRunsMillis(30000L);
this.setNumTestsPerEvictionRun(-1);
}
}
4. JedisPool 参数说明( 摘自 阿里云 JedisPool资源池优化)
Jedis连接就是连接池中JedisPool管理的资源,JedisPool保证资源在一个可控范围内,并且保障线程安全。使用合理的GenericObjectPoolConfig配置能够提升Redis的服务性能,降低资源开销。详情可以点击链接查看
推荐配置: