连接池:别让连接池帮了倒忙
连接池技术在业务项目中扮演着重要角色,尤其是在数据库连接池、Redis连接池和HTTP连接池的使用上。今天,我们将围绕连接池的结构、使用和配置,知美网源码以及如何避免常见错误,来深入探讨这一话题。
连接池的结构主要包括对外提供连接获取与归还接口的客户端使用,以及内部实现的连接建立、连接心跳保持、连接管理、空闲连接回收、连接可用性检测等功能。在业务项目中,数据库连接池、Redis连接池和HTTP连接池是dnfc 源码最常见的三种连接池。
在使用第三方客户端SDK进行网络通信时,首先需要确认SDK是否基于连接池技术实现。TCP作为面向连接的基于字节流的协议,如果SDK没有使用连接池,而是直接建立TCP连接,将需要考虑每次连接的开销,并且在多线程环境下可能产生线程安全问题。因此,yersinia源码识别SDK连接池的实现方式至关重要。
以Jedis作为Redis操作最常见的库为例,分析其源码。Jedis类是连接池与连接分离的API,内部维护一个Socket连接,多线程环境下复用连接可能导致命令执行不完整或线程安全问题。使用连接池如JedisPool,可以实现线程安全的人事 源码复用,避免这些问题。确保关闭连接池,最好通过shutdownhook在程序退出时释放资源。
连接池的配置不是一成不变的。最大连接数的设置需要根据容量规划,过大或过小都会影响性能。通过实践和监控,可以有效调整参数,bytebuf 源码满足性能需求同时避免资源浪费。连接池的正确使用方式包括复用连接和确保在程序退出前关闭连接池。
总结来说,理解连接池的实现方式、正确使用姿势和合理配置参数是确保高效、稳定的连接管理的关键。连接池技术能够显著提升性能,减少资源浪费,因此正确应用连接池对于提高系统性能至关重要。
Jedis连接池究竟是何物?
连接池是管理并回收资源的对象集合,以减少系统资源的创建和销毁开销,提升系统吞吐量,适用于创建/销毁资源耗时的场景。以Jedis为例,其底层使用的是GenericObjectPool作为连接池实现。业务从空闲连接队列获取连接,最长等待时间由maxWaitMillis决定。获取后,检查是否有效,关闭后再次放入空闲队列或销毁。连接池的参数如配置文件中详细列出,Spring-Data-Redis将参数进行收敛,用户主要配置参数较少,关键参数包括验证方法的启用和关闭。Jedis实例通过Spring-Data-Redis封装后,实现对连接池的管理,提供了BorrowObject方法获取连接和ReturnObject方法归还连接。其中BorrowObject方法可能从空闲队列获取或创建新连接,超过最大等待时间则抛出异常。ReturnObject方法负责归还连接并进行有效性验证。连接池还包括定期驱逐/保活机制、检查机制和抛弃机制,通过配置参数、源码分析和JMX工具实现连接状态监控和问题排查。了解连接池原理有助于提升资源管理效率,并在实际应用中根据业务需求优化配置。
å°åºå¦ä½å¨springä¸ä½¿ç¨redis
1. Redis使ç¨åºæ¯
Redisæ¯ä¸ä¸ªå¼æºç使ç¨ANSI Cè¯è¨ç¼åãæ¯æç½ç»ãå¯åºäºå å亦å¯æä¹ åçæ¥å¿åãKey-Valueæ°æ®åºï¼å¹¶æä¾å¤ç§è¯è¨çAPIã
æ们é½ç¥éï¼å¨æ¥å¸¸çåºç¨ä¸ï¼æ°æ®åºç¶é¢æ¯æ容æåºç°çãæ°æ®é太大åé¢ç¹çæ¥è¯¢ï¼ç±äºç£çIOæ§è½çå±éæ§ï¼å¯¼è´é¡¹ç®çæ§è½è¶æ¥è¶ä½ã
è¿æ¶åï¼åºäºå åçç¼åæ¡æ¶ï¼å°±è½è§£å³æ们å¾å¤é®é¢ãä¾å¦Memcacheï¼Redisçãå°ä¸äºé¢ç¹ä½¿ç¨çæ°æ®æ¾å ¥ç¼å读åï¼å¤§å¤§éä½äºæ°æ®åºçè´æ ãæåäºç³»ç»çæ§è½ã
å ¶å®ï¼å¯¹äºhibernateçäºçº§ç¼åï¼æ¯åæ ·çéçãå©ç¨å åé«éç读åé度ï¼æ¥è§£å³ç¡¬ççç¶é¢ã
2. é 置使ç¨redis
é¦å ï¼æ们éè¦å¼å ¥åºæ¬çjarå ãmavenä¸çåºæ¬å¼ç¨å¦ä¸ï¼
ãããã<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.4.2.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.6.2</version>
</dependency>
ç¶åï¼å¨applicationContextä¸é ç½®å¦ä¸:
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${ redis.maxIdle}" />
<property name="maxTotal" value="${ redis.maxActive}" />
<property name="maxWaitMillis" value="${ redis.maxWait}" />
<property name="testOnBorrow" value="${ redis.testOnBorrow}" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="${ redis.host}" p:port="${ redis.port}" p:password="${ redis.pass}"
p:pool-config-ref="poolConfig" />
<bean id="stringSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<!-- å¼å¯äºå¡ï¼å¯ä»¥éè¿transcational注解æ§å¶ -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="keySerializer" ref="stringSerializer" />
<property name="enableTransactionSupport" value="true" />
</bean>
对äºhibernateçé ç½®å¯ç¥ï¼ç¬¬ä¸ä¸ªpoolconfigæ¯å¯¹è¿æ¥æ± çé ç½®ãå æ¬æ大è¿æ¥æ°ï¼éåæ°ï¼åæ´»æ¶é´ï¼æ大çå¾ æ¶é´ççï¼è¿æä¸äºé¢å¤çé ç½®ï¼è¯·ç´æ¥ç¹å»JedisPoolConfigç±»æºç ï¼è¿è¡æ¥çã
è¿äºé ç½®çææå¦æä¸æç½çè¯ï¼ä¸å®è¦å»æ线ç¨æ± 好好å¦ä¹ ä¸ã
第ä¸ä¸ªé ç½®æ¯è¿æ¥å·¥åï¼é¡¾åæä¹ï¼æåºæ¬ç使ç¨ä¸å®æ¯å¯¹è¿æ¥çæå¼åå ³éãæ们éè¦ä¸ºå ¶é ç½®redisæå¡å¨çè´¦æ·å¯ç ï¼ç«¯å£å·ãï¼è¿éè¿å¯ä»¥é ç½®æ°æ®åºçindexï¼ä½æ¯æ使ç¨æ¶åä¸ç´ä½¿ç¨redisçé»è®¤æ°æ®åºï¼ä¹å°±æ¯ç¬¬0个ï¼
æåä¸ä¸ªé ç½®ç¹å«éè¦ãè¿ä¸ªç±»ä¼¼äºspringæä¾çHibernateDaoSupportã
æ¥ä¸æ¥ï¼å ¨é¨è®²è§£é½å°å´ç»è¿ä¸ªç±»å±å¼ã
3. RedisTemplateç使ç¨
è¿ä¸ªç±»ä½ä¸ºä¸ä¸ªæ¨¡çç±»ï¼æä¾äºå¾å¤å¿«é使ç¨redisçapiï¼èä¸éè¦èªå·±æ¥ç»´æ¤è¿æ¥ï¼äºå¡ã
æåçæ¶åï¼æå建çBaseRedisDaoæ¯ç»§æ¿èªè¿ä¸ªç±»çã继æ¿ç好å¤æ¯æçæ¯ä¸ªDaoä¸ï¼é½å¯ä»¥èªç±çæ§å¶åºååå¨ï¼èªç±çæ§å¶èªå·±æ¯å¦éè¦äºå¡ï¼è¿ä¸ªå ä¸éè¦äºè§£ï¼è·çæç®åçè¿ç§é ç½®æ¹æ³æ¥å³å¯ã
templateæä¾äºä¸ç³»åçoperation,æ¯å¦valueOperation,HashOperation,ListOperation,SetOperationçï¼ç¨æ¥æä½ä¸åæ°æ®ç±»åçRedisã
并ä¸ï¼RedisTemplateè¿æä¾äºå¯¹åºç*OperationsEditorï¼ç¨æ¥éè¿RedisTemplateç´æ¥æ³¨å ¥å¯¹åºçOperationãæ们ææ¶ä¸è®²è¿ä¸ªã
对äºä¸é¢çtest1æ¹æ³ï¼æ们ææ¶ä¸ç¨èèï¼å äºè§£éè¿RedisTemplateæ¥ä½¿ç¨connectionæä½Redisã
Test代ç å¦ä¸ï¼
package cn.test.spjedis;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.cn.redis2.dao.IncrDao;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestRedis {
@Resource(name = "redisTemplate")
private RedisTemplate<String, String> template; // inject the template as ListOperations
//è³äºè¿ä¸ªä¸ºä»ä¹å¯ä»¥æ³¨å ¥ãéè¦åèAbstractBeanFactory doGetBean
//super.setValue(((RedisOperations) value).opsForValue());å°±è¿ä¸è¡ä»£ç ä¾é ä¸ä¸ªeditor
@Resource(name = "redisTemplate")
private ValueOperations<String, Object> vOps;
public void testSet(){
template.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
byte [] key = "tempkey".getBytes();
byte[] value = "tempvalue".getBytes();
connection.set(key, value);
return true;
}
});
}
public void testSet1(){
vOps.set("tempkey", "tempvalue");
}
@Autowired
private IncrDao incr;
@Test
public void addLink() {
System.out.println(incr.incr());
System.out.println(incr.get());
}
}
è¿ä¸ªæ¯å¯¹Stringç±»åæå ¥ç两个æµè¯ãtestæ¹æ³ä¸ï¼ä½¿ç¨äºæ¨¡çç±»æ交åè°(RedisCallBack)çæ¹æ³æ¥ä½¿ç¨jedis connectionæä½æ°æ®ãè¿ä¸é¨åï¼æ没æä¼¼æ¾ç¸è¯å¢ï¼
HibernateTemplateçHibernateCallbackï¼ä»¥åHibernate Sessionç±»ä¸çdoWork以ådoReturningWorkæ¹æ³ï¼é½æ¯ä½¿ç¨äºè¿æ ·çæºå¶ï¼æ¹ä¾¿å¯¹äºè¿æ¥æè sessionçç»ä¸ç®¡çã
public int excuteHqlUpdate(final String hql,final Object ...params){
return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
@Override
@SuppressWarnings("unchecked")
public Integer doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(hql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
queryObject.setParameter(i, params[i]);
}
}
return queryObject.executeUpdate();
}
});
}
jedis å strpin-data-redis åªä¸ä¸ªå¥½
ä¹åä¸ç´æ²¡ä»ç»çè¿ShardedJedisç代ç ï¼æè¿éå°äºshardåé群æ©å®¹åçæ°æ®è¿ç§»é®é¢ã
ä»å¤©å¨çShardedJedisæºç çæ¶åï¼åç°ShardedJedis并没æ使ç¨èç¹çIpåportåhashï¼èæ¯ç¨çinstanceç顺åºæè nameï¼å¤ªèµäºã
private void initialize(List<S> shards) {
nodes = new TreeMap<Long, S>();
for (int i = 0; i != shards.size(); ++i) {
final S shardInfo = shards.get(i);
if (shardInfo.getName() == null)
for (int n = 0; n < * shardInfo.getWeight(); n++) {
nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n),
shardInfo);
}
else
for (int n = 0; n < * shardInfo.getWeight(); n++) {
nodes.put(
this.algo.hash(shardInfo.getName() + "*"
+ shardInfo.getWeight() + n), shardInfo);
}
resources.put(shardInfo, shardInfo.createResource());
}
}
é ç½®çæ¶åä¹é常ç®å:
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value=""/>
<property name="maxIdle" value=""/>
<property name="minIdle" value="1"/>
<property name="maxWaitMillis" value=""/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
</bean>
<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" destroy-method="destroy">
<constructor-arg ref="jedisPoolConfig"/>
<constructor-arg>
<list>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg value=".0.0.1"/>
<constructor-arg type="int" value=""/>
<constructor-arg value="instance:"/>
</bean>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg value=".0.0.1"/>
<constructor-arg type="int" value=""/>
<constructor-arg value="instance:"/>
</bean>
<bean class="redis.clients.jedis.JedisShardInfo">
<constructor-arg value=".0.0.1"/>
<constructor-arg type="int" value=""/>
<constructor-arg value="instance:"/>
</bean>
</list>
</constructor-arg>
</bean>
ä¸å¼å§ä½ å¯ä»¥è®¾ç½®è¶³å¤å¤çinstanceï¼æ°æ®æ©å®¹çæ¶åï¼åªéè¦å°å 个instanceçæ°æ®copyå°å«çæºå¨ä¸ã
ç¶åä¿®æ¹é ç½®æ件çipå端å£å³å¯ãå¾æ¹ä¾¿å§ï¼
å¦å¤ï¼Jedisè¿æä¾äºå¯¹jedis sentinel poolçå°è£ ï¼æ以åç主ä»åæ¢çæ¶åï¼web serveré½ä¸éè¦éæ°é ç½®ådeployãé«å¯ç¨æ§çæä½³ä½ç°åã
@Autowired private JedisSentinelPool pool;
public void mymethod() {
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.hset(....
} catch (JedisException je) {
throw je;
} finally {
if (jedis != null) pool.returnResource(jedis);
}
}
spring beançé ç½®ï¼
<bean id="redisSentinel" class="redis.clients.jedis.JedisSentinelPool">
<constructor-arg index="0" value="mymaster" />
<constructor-arg index="1">
<set>
<value>hostofsentinel:</value>
</set>
</constructor-arg>
<constructor-arg index="2" ref="jedisPoolConfig" />
</bean>
2024-11-20 07:12
2024-11-20 06:52
2024-11-20 06:16
2024-11-20 06:12
2024-11-20 04:49