解决使用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######"); } publicRedisTemplate redisTemplateObject(IntegerdbIndex)throwsException{ RedisTemplate redisTemplateObject=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(RedisTemplate template){ 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高并发下连接池满的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。