解决使用redisTemplate高并发下连接池满的问题
用JMeter进行高并发测试的时候,发现报错:
org.springframework.data.redis.RedisConnectionFailureException:CannotgetJedisconnection;
nestedexceptionisredis.clients.jedis.exceptions.JedisException:Couldnotgetaresourcefromthepool
连不上redis,是因为连接池不够用了
我用的是redisTemplate来操作redis,而redisTemplate并不会自动释放连接
有一个方法,就是加大最大连接数,但是治标不治本,加到redis.maxIdle=1000了,看似够大了,但连接数一直在增加,迟早会崩
找了很久,最后发现这个方法可用
在使用redisTemplate的部分用try-catch-finally包起来
在catch-finally中加上,手动断开连接,现在就不会报错了
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
现在设置最大连接数redis.maxIdle=100也没事了
在redis-cli中输入infoclients现在的连接数大概在二三十左右
补充知识:Redis配置连接池,redisTemplate操作多个db数据库,切换多个db,解决JedisConnectionFactory的设置连接方法过时问题。
环境
1、springmvc
2、jdk1.8
3、maven
redis.properties配置文件
#redissetting redis.host=localhost redis.port=6379 redis.password= redis.maxIdle=200 redis.minIdle=0 redis.maxActive=50 redis.maxWait=10000 redis.testOnBorrow=true redis.timeout=100000 #定义需要使用的db //#sessionCodeDB sessionCodeDb=0 //#车辆基本信息DB bicycleInfoDb=15 //#当前位置信息DB currentLocationDb=14 //#锁车/解锁DB lockDb=13 //#根据车牌获取电子车牌DB ebikeNoDb=12 //#根据电子车牌获取车牌DB bikeNoDb=11
pom.xml依赖
UTF-8 5.1.2.RELEASE org.springframework spring-context ${spring.version} org.springframework spring-context-support ${spring.version} org.springframework spring-core ${spring.version} org.springframework spring-web ${spring.version} org.springframework spring-webmvc ${spring.version} redis.clients jedis 2.9.3 org.springframework.data spring-data-redis 2.0.14.RELEASE com.alibaba fastjson 1.2.11 net.sf.json-lib json-lib 2.4 jdk15
RedisConfig.java配置类初始化redis连接池
importcom.fasterxml.jackson.annotation.JsonAutoDetect;
importcom.fasterxml.jackson.annotation.PropertyAccessor;
importcom.fasterxml.jackson.databind.ObjectMapper;
importlombok.extern.slf4j.Slf4j;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.data.redis.connection.RedisConnectionFactory;
importorg.springframework.data.redis.connection.RedisPassword;
importorg.springframework.data.redis.connection.RedisStandaloneConfiguration;
importorg.springframework.data.redis.connection.jedis.JedisClientConfiguration;
importorg.springframework.data.redis.connection.jedis.JedisConnectionFactory;
importorg.springframework.data.redis.core.RedisTemplate;
importorg.springframework.data.redis.core.ValueOperations;
importorg.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
importorg.springframework.data.redis.serializer.RedisSerializer;
importorg.springframework.data.redis.serializer.StringRedisSerializer;
importorg.springframework.stereotype.Component;
importredis.clients.jedis.JedisPoolConfig;
importjavax.annotation.PostConstruct;
importjava.io.Serializable;
importjava.util.HashMap;
importjava.util.Map;
importjava.util.concurrent.TimeUnit;
@Component
@Slf4j
publicclassRedisConfig{
@Value("${redis.host}")
privateStringhostName;
@Value("${redis.port}")
privateintport;
@Value("${redis.password}")
privateStringpassWord;
@Value("${redis.maxIdle}")
privateintmaxIdl;
@Value("${redis.minIdle}")
privateintminIdl;
@Value("${redis.timeout}")
privateinttimeout;
@Value("${sessionCodeDb}")
privateintsessionCodeDb;
@Value("${bicycleInfoDb}")
privateintbicycleInfoDb;
@Value("${currentLocationDb}")
privateintcurrentLocationDb;
@Value("${lockDb}")
privateintlockDb;
@Value("${ebikeNoDb}")
privateintebikeNoDb;
@Value("${bikeNoDb}")
privateintbikeNoDb;
publicstaticMap>redisTemplateMap=newHashMap<>();
@PostConstruct
publicvoidinitRedisTemp()throwsException{
log.info("######START初始化Redis连接池START######");
redisTemplateMap.put(sessionCodeDb,redisTemplateObject(sessionCodeDb));
redisTemplateMap.put(bicycleInfoDb,redisTemplateObject(bicycleInfoDb));
redisTemplateMap.put(currentLocationDb,redisTemplateObject(currentLocationDb));
redisTemplateMap.put(lockDb,redisTemplateObject(lockDb));
redisTemplateMap.put(ebikeNoDb,redisTemplateObject(ebikeNoDb));
redisTemplateMap.put(bikeNoDb,redisTemplateObject(bikeNoDb));
log.info("######END初始化Redis连接池END######");
}
publicRedisTemplateredisTemplateObject(IntegerdbIndex)throwsException{
RedisTemplateredisTemplateObject=newRedisTemplate();
redisTemplateObject.setConnectionFactory(redisConnectionFactory(jedisPoolConfig(),dbIndex));
setSerializer(redisTemplateObject);
redisTemplateObject.afterPropertiesSet();
returnredisTemplateObject;
}
/**
*连接池配置信息
*@return
*/
publicJedisPoolConfigjedisPoolConfig(){
JedisPoolConfigpoolConfig=newJedisPoolConfig();
//最大连接数
poolConfig.setMaxIdle(maxIdl);
//最小空闲连接数
poolConfig.setMinIdle(minIdl);
poolConfig.setTestOnBorrow(true);
poolConfig.setTestOnReturn(true);
poolConfig.setTestWhileIdle(true);
poolConfig.setNumTestsPerEvictionRun(10);
poolConfig.setTimeBetweenEvictionRunsMillis(60000);
//当池内没有可用的连接时,最大等待时间
poolConfig.setMaxWaitMillis(10000);
//------其他属性根据需要自行添加-------------
returnpoolConfig;
}
/**
*jedis连接工厂
*@paramjedisPoolConfig
*@return
*/
publicRedisConnectionFactoryredisConnectionFactory(JedisPoolConfigjedisPoolConfig,intdb){
//单机版jedis
RedisStandaloneConfigurationredisStandaloneConfiguration=
newRedisStandaloneConfiguration();
//设置redis服务器的host或者ip地址
redisStandaloneConfiguration.setHostName(hostName);
//设置默认使用的数据库
redisStandaloneConfiguration.setDatabase(db);
//设置密码
redisStandaloneConfiguration.setPassword(RedisPassword.of(passWord));
//设置redis的服务的端口号
redisStandaloneConfiguration.setPort(port);
//获得默认的连接池构造器(怎么设计的,为什么不抽象出单独类,供用户使用呢)
JedisClientConfiguration.JedisPoolingClientConfigurationBuilderjpcb=
(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();
//指定jedisPoolConifig来修改默认的连接池构造器(真麻烦,滥用设计模式!)
jpcb.poolConfig(jedisPoolConfig);
//通过构造器来构造jedis客户端配置
JedisClientConfigurationjedisClientConfiguration=jpcb.build();
//单机配置+客户端配置=jedis连接工厂
returnnewJedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfiguration);
}
privatevoidsetSerializer(RedisTemplatetemplate){
Jackson2JsonRedisSerializer
在其他类中的使用
@Autowired
privateRedisConfigredisUtil;
//#获取db0数据库的数据
publicstaticIntegersessionCodeDb=0;
/**
*根据sessionCode获取userId
*@paramsessionCode
*@return
*/
publicStringgetUserIdBySessionCode(StringsessionCode){
try{
Objectobj=redisUtil.get(sessionCode,sessionCodeDb);
if(obj!=null){
returnobj.toString();
}else{
returnnull;
}
}catch(Exceptione){
e.printStackTrace();
returnnull;
}
}
以上这篇解决使用redisTemplate高并发下连接池满的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。