解决使用redisTemplate高并发下连接池满的问题

网友投稿 1032 2022-11-10


解决使用redisTemplate高并发下连接池满的问题

用JMeter进行高并发测试的时候,发现报错:

org.springframework.data.redis.RedisConnectionFailueRcykXreException: Cannot get Jedis connection;

nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool

连不上redis,是因为连接池不够用了

我用的是redisTemplate来操作redis,而redisTemplate并不会自动释放连接

有一个方法,就是加大最大连接数,但是治标不治本,加到redis.maxIdle=1000了,看似够大了,但连接数一直在增加,迟早会崩

找了很久,最后发现 这个方法可用

在使用redisTemplate的部分用try-catch-finally包起来

在catch-finally中加上,手动断开连接,现在就不会报错了

RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());

现在设置最大连接数redis.maxIdle=100也没事了

在redis-cli中输入 info clients 现在的连接数大概在二三十左右

补充知识:Redis 配置连接池,redisTemplate 操作多个db数据库,切换多个db,解决JedisConnectionFactory的设置连接方法过时问题。

环境

1、springmvc

2、jdk1.8

3、maven

redis.properties配置文件

#redis setting

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

//#sessionCode DB

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连接池

import com.fasterxml.jackson.annotation.JsonAutoDetect;

import com.fasterxml.jackson.annotation.PropertyAccessor;

import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.data.redis.connection.RedisConnectionFactory;

import org.springframework.data.redis.connection.RedisPassword;

import org.springframework.data.redis.connection.RedisStandaloneConfiguration;

import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;

import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;

import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.core.ValueOperations;

import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;

import org.springframework.data.redis.serializer.RedisSerializer;

import org.springframework.data.redis.serializer.StringRedisSerializer;

import org.springframework.stereotype.Component;

import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;

import java.io.Serializable;

import java.util.HashMap;

import java.util.Map;

import java.util.concurrent.TimeUnit;

@Component

@Slf4j

public class RedisConfig {

@Value("${redis.host}")

private String hostName;

@Value("${redis.port}")

private int port;

@Value("${redis.password}")

private String passWord;

@Value("${redis.maxIdle}")

private int maxIdl;

@Value("${redis.minIdle}")

private int minIdl;

@Value("${redis.timeout}")

private int timeout;

@Value("${sessionCodeDb}")

private int sessionCodeDb;

@Value("${bicycleInfoDb}")

private int bicycleInfoDb;

@Value("${currentLocationDb}")

private int currentLocationDb;

@Value("${lockDb}")

private int lockDb;

@Value("${ebikeNoDb}")

private int ebikeNoDb;

@Value("${bikeNoDb}")

private int bikeNoDb;

public static Map> redisTemplateMap = new HashMap<>();

@PostConstruct

public void initRedisTemp() throws Exception{

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 ######");

}

public RedisTemplate redisTemplateObject(Integer dbIndex) throws Exception {

RedisTemplate redisTemplateObject = new RedisTemplate();

redisTemplateObject.setConnectionFactory(redisConnectionFactory(jedisPoolConfig(),dbIndex));

setSerializer(redisTemplateObject);

redisTemplateObject.afterPropertiesSet();

return redisTemplateObject;

}

/**

* 连接池配置信息

* @return

*/

public JedisPoolConfig jedisPoolConfig() {

JedisPoolConfig poolConfig=new JedisPoolConfig();

//最大连接数

poolConfig.setMaxIdle(maxIdl);

//最小空闲连接数

poolConfig.setMinIdle(minIdl);

poolConfig.setTestOnBorrow(true);

poolConfig.setTestOnReturn(true);

poolConfig.setTestWhileIdle(true);

poolConfig.setNumTestsPerEvictionRun(10);

poolConfig.setTimeBetweenEvictionRunsMillis(60000);

//当池内没有可用的连接时,最大等待时间

poolConfig.setMaxWaitMillis(10000);

//------其他属性根据需要自行添加-------------

return poolConfig;

}

/**

* jedis连接工厂

* @param jedisPoolConfig

* @return

*/

public RedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig,int db) {

//单机版jedis

RedisStandaloneConfiguration redisStandaloneConfiguration =

new RedisStandaloneConfiguration();

//设置redis服务器的host或者ip地址

redisStandaloneConfiguration.setHostName(hostName);

//设置默认使用的数据库

redisStandaloneConfiguration.setDatabase(db);

//设置密码

redisStandaloneConfiguration.setPassword(RedisPassword.of(passWord));

//设置redis的服务的端口号

redisStandaloneConfiguration.setPort(port);

//获得默认的连接池构造器(怎么设计的,为什么不抽象出单独类,供用户使用呢)

JedisClientConfiguration.JedisPoolingClientConfigurationBuilder jpcb =

(JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)JedisClientConfiguration.builder();

//指定jedisPoolConifig来修改默认的连接池构造器(真麻烦,滥用设计模式!)

jpcb.poolConfig(jedisPoolConfig);

//通过构造器来构造jedis客户端配置

JedisClientConfiguration jedisClientConfiguration = jpcb.build();

//单机配置 + 客户端配置 = jedis连接工厂

return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);

}

private void setSerializer(RedisTemplate template) {

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(

Object.class);

ObjectMapper om = new ObjectMapper();

om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

jackson2JsonRedisSerializer.setObjectMapper(om);

template.setKeySerializer(template.getStringSerializer());

template.setValueSerializer(jackson2JsonRedisSerializer);

template.setHashValueSerializer(jackson2JsonRedisSerializer);

//在使用String的数据结构的时候使用这个来更改序列化方式

RedisSerializer stringSerializer = new StringRedisSerializer();

template.setKeySerializer(stringSerializer );

template.setValueSerializer(stringSerializer );

template.setHashKeySerializer(stringSerializer );

template.setHashValueSerializer(stringSerializer );

}

/**

* 删除对应的value

* @param key

*/

public void remove(final String key,int db) {

RedisTemplate redisTemplate = getRedisTemplateByDb(db);

if (exists(key,redisTemplate)) {

redisTemplate.delete(key);

}

}

/**

* 判断缓存中是否有对应的value

* @param key

* @return

*/

public boolean exists(final String key,RedisTemplate redisTemplate) {

return redisTemplate.hasKey(key);

}

/**

* 读取缓存

* @param key

* @return

*/

public Object get(final String key,int db) {

RedisTemplate redisTemplate = getRedisTemplateByDb(db);

Object result = null;

ValueOperations operations = redisTemplate.opsForValue();

result = operations.get(key);

return result;

}

/**

* 写入缓存

* @param key

* @param value

* @return

*/

public boolean set(final String key, Object value,int db) {

RedisTemplate redisTemplate = getRedisTemplateByDb(db);

boolean result = false;

try {

ValueOperations operations = redisTemplate.opsForValue();

operations.set(key, valhttp://ue);

result = true;

} catch (Exception e) {

log.error("set cache error", e);

}

return result;

}

/**

* 根据key 获取过期时间

* @param key 键 不能为null

* @return 返回0代表为永久有效

*/

public long getExpire(String key,TimeUnit unit,int db) {

RedisTemplate redisTemplate = getRedisTemplateByDb(db);

return redisTemplate.getExpire(key, unit);

}

/**

* 根据db 获取对应的redisTemplate实例

* @param db

* @return

*/

public RedisTemplate getRedisTemplateByDb(int db){

return redisTemplateMap.get(db);

}

}

在其他类中的使用

@Autowired

private RedisConfig redisUtil;

//#获取db0 数据库的数据

public static Integer sessionCodeDb = 0;

/**

* 根据sessionCode获取userId

* @param sessionCode

* @return

*/

public String getUserIdBySessionCode(String sessionCode){

try {

Object obj = redisUtil.get(sessionCode,sessionCodeDb);

if(obj!=null) {

return obj.toString();

}else{

return null;

}

}catch (Exception e){

e.printStackTrace();

return null;

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java Matcher匹配头尾截取替换字符串的案例
下一篇:解决idea中maven项目无端显示404错误的方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~