springboot工程启动报错,redis异常:
org.springframework.dao.InvalidDataAccessApiUsageException: Could not get a resource from the pool; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:70) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.jedis.JedisExceptionConverter.convert(JedisExceptionConverter.java:41) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.jedis.JedisClusterConnection.convertJedisAccessException(JedisClusterConnection.java:760) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.jedis.JedisClusterStringCommands.convertJedisAccessException(JedisClusterStringCommands.java:556) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.jedis.JedisClusterStringCommands.set(JedisClusterStringCommands.java:120) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.DefaultedRedisConnection.set(DefaultedRedisConnection.java:274) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.connection.DefaultStringRedisConnection.set(DefaultStringRedisConnection.java:946) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:61) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at com.sun.proxy.$Proxy94.set(Unknown Source) ~[?:?]
at com.onmet.data.log.deal.datadeal.config.redis.RedisServiceImpl$1.doInRedis(RedisServiceImpl.java:45) ~[classes!/:0.0.1-SNAPSHOT]
at com.onmet.data.log.deal.datadeal.config.redis.RedisServiceImpl$1.doInRedis(RedisServiceImpl.java:41) ~[classes!/:0.0.1-SNAPSHOT]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:224) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:171) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
at com.onmet.data.log.deal.datadeal.config.redis.RedisServiceImpl.set(RedisServiceImpl.java:41) ~[classes!/:0.0.1-SNAPSHOT]
at com.onmet.data.log.deal.datadeal.config.redis.RedisServiceImpl.setList(RedisServiceImpl.java:125) ~[classes!/:0.0.1-SNAPSHOT]
at com.onmet.data.log.deal.datadeal.commandLineRunner.HdfsRunner.run(HdfsRunner.java:64) [classes!/:0.0.1-SNAPSHOT]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.5.RELEASE.jar!/:2.1.5.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.5.RELEASE.jar!/:2.1.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.5.RELEASE.jar!/:2.1.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.5.RELEASE.jar!/:2.1.5.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.5.RELEASE.jar!/:2.1.5.RELEASE]
at com.onmet.data.log.deal.datadeal.DatadealApplication.main(DatadealApplication.java:12) [classes!/:0.0.1-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_151]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_151]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [md_dt_20191210-082526.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [md_dt_20191210-082526.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [md_dt_20191210-082526.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [md_dt_20191210-082526.jar:0.0.1-SNAPSHOT]
Caused by: redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:51) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.java:66) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:116) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisClusterCommand.runBinary(JedisClusterCommand.java:60) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.BinaryJedisCluster.set(BinaryJedisCluster.java:77) ~[jedis-2.9.0.jar!/:?]
at org.springframework.data.redis.connection.jedis.JedisClusterStringCommands.set(JedisClusterStringCommands.java:118) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
... 30 more
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:439) ~[commons-pool2-2.6.2.jar!/:2.6.2]
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:349) ~[commons-pool2-2.6.2.jar!/:2.6.2]
at redis.clients.util.Pool.getResource(Pool.java:49) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisSlotBasedConnectionHandler.getConnectionFromSlot(JedisSlotBasedConnectionHandler.java:66) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:116) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.JedisClusterCommand.runBinary(JedisClusterCommand.java:60) ~[jedis-2.9.0.jar!/:?]
at redis.clients.jedis.BinaryJedisCluster.set(BinaryJedisCluster.java:77) ~[jedis-2.9.0.jar!/:?]
at org.springframework.data.redis.connection.jedis.JedisClusterStringCommands.set(JedisClusterStringCommands.java:118) ~[spring-data-redis-2.1.8.RELEASE.jar!/:2.1.8.RELEASE]
... 30 more
排查后发现,工程接入的是redisCluster,使用jedis连接池管理redis连接。
Jedis实际上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池。
异常表明:redis无法从连接池中获取连接,排查后,发现连接池属性配置异常,改成如下配置即可:
spring.redis.cluster.nodes=10.1.10.14:7000,10.1.10.14:7001,10.1.10.14:7002
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
另外,springboot2.0之后,jedis被lettuce取代,变成默认连接客户端,Lettuce是基于Netty的,支持多个线程间并发访问,连接StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。