Background: Recently, I was doing a stress test on the Springboot system developed by Yixin. I found that when I first started the stress test, I could access data from the redis cluster normally. However, after a few minutes of pause, and then I continued to use jmeter to perform the stress test, I found that Redis started to suddenly and crazyly burst out abnormal prompts: Command timed out after 6 second(s)...
1 Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 6 second(s) 2 at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51) 3 at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:114) 4 at io.lettuce.core.cluster.ClusterFutureSyncInvocationHandler.handleInvocation(ClusterFutureSyncInvocationHandler.java:123) 5 at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80) 6 at com.sun.proxy.$Proxy134.mget(Unknown Source) 7 at org.springframework.data.redis.connection.lettuce.LettuceStringCommands.mGet(LettuceStringCommands.java:119) 8 ... 15 common frames omitted
I hurriedly checked the redis cluster and found that all nodes in the cluster were normal, and the CPU and memory usage were It’s less than 20%. Looking at all this, I suddenly fell into a long meditation. What is the problem? After searching on Baidu, I found that many people have experienced similar situations. Some people said that the timeout setting should be changed. A bigger one will do the trick. I followed this solution and set the timeout value to a larger value, but the timeout problem was still not solved.
Among them, the dependency package for springboot to operate redis is——
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 </dependency>
Cluster configuration——
1 redis: 2 timeout: 6000ms 3 cluster: 4 nodes: 5 - xxx.xxx.x.xxx:6379 6 - xxx.xxx.x.xxx:6379 7 - xxx.xxx.x.xxx:6379 8 jedis: 9 pool: 10 max-active: 1000 11 max-idle: 10 12 min-idle: 5 13 max-wait: -1
Click on spring-boot-starter-data-redis and find it inside Contains lettuce dependencies:
springboot1.x uses jedis by default, and springboot2.x uses lettuce by default. We can simply verify that in the redis driver loading configuration class, output the RedisConnectionFactory information:
1 @Configuration 2 @AutoConfigureAfter(RedisAutoConfiguration.class) 3 public class Configuration { 4 @Bean 5 public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) { 6 log.info("测试打印驱动类型:"+factory); 7 }
Print output——
测试打印驱动类型:org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@74ee761e
It can be seen that the lettuce driver connection is used here , therefore, when it is replaced with the jedis driver connection that was used frequently before, the problem of Command timed out after 6 second(s) no longer occurs.
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 <exclusions> 5 <exclusion> 6 <groupId>io.lettuce</groupId> 7 <artifactId>lettuce-core</artifactId> 8 </exclusion> 9 </exclusions> 10 </dependency> 11 <dependency> 12 <groupId>redis.clients</groupId> 13 <artifactId>jedis</artifactId> 14 </dependency>
Then the question is, how does Springboot2.x use lettuce by default? We need to study some of the code inside. We can enter the redis part of the Springboot2. ##
1 @Configuration( 2 proxyBeanMethods = false 3 ) 4 @ConditionalOnClass({RedisOperations.class}) 5 @EnableConfigurationProperties({RedisProperties.class}) 6 @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) 7 public class RedisAutoConfiguration { 8 public RedisAutoConfiguration() { 9 } 10 ......省略 11 }
1 2 @Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class}) 3
1 //LettuceConnectionConfiguration 2 @ConditionalOnClass({RedisClient.class}) 3 class LettuceConnectionConfiguration extends RedisConnectionConfiguration { 4 ......省略 5 @Bean 6 @ConditionalOnMissingBean({RedisConnectionFactory.class}) 7 LettuceConnectionFactory redisConnectionFactory(ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers, ClientResources clientResources) throws UnknownHostException { 8 LettuceClientConfiguration clientConfig = this.getLettuceClientConfiguration(builderCustomizers, clientResources, this.getProperties().getLettuce().getPool()); 9 return this.createLettuceConnectionFactory(clientConfig); 10 } 11 } 12 //JedisConnectionConfiguration 13 @ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class}) 14 class JedisConnectionConfiguration extends RedisConnectionConfiguration { 15 ......省略 16 @Bean 17 @ConditionalOnMissingBean({RedisConnectionFactory.class}) 18 JedisConnectionFactory redisConnectionFactory(ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) throws UnknownHostException { 19 return this.createJedisConnectionFactory(builderCustomizers); 20 } 21 } 22
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 <exclusions> 5 <exclusion> 6 <groupId>io.lettuce</groupId> 7 <artifactId>lettuce-core</artifactId> 8 </exclusion> 9 </exclusions> 10 </dependency>
In this way, when performing the import annotation of RedisAutoConfiguration, because the lettuce dependency is not found, this annotation @Import({LettuceConnectionConfiguration.class , the JedisConnectionConfiguration in the second position of JedisConnectionConfiguration.class}) is now valid and can be registered to the container as the driver for springboot to operate redis.
What is the difference between lettuce and jedis?
lettuce: The bottom layer is implemented in netty, thread-safe, and has only one instance by default. jedis: Can be directly connected to the redis server and used with the connection pool to increase physical connections. Find the error method according to the exception prompt, lettuceConverters.toBoolean(this.getConnection().zadd(key, score, value)) in the following code——1 <dependency> 2 <groupId>redis.clients</groupId> 3 <artifactId>jedis</artifactId> 4 </dependency>
LettuceConverters.toBoolean() converts long to Boolean. Under normal circumstances, this.getConnection().zadd(key, score, value) returns 1 if the addition is successful, so LettuceConverters.toBoolean(1) gets is true, otherwise, if the new addition fails, 0 is returned, that is, LettuceConverters.toBoolean(0). There is also a third case, that is, an exception occurs in this.getConnection().zadd(key, score, value) method. What? What happens if an exception occurs?
It should be when the connection connection fails.
The above is the detailed content of How to solve the timeout exception when Springboot2.x integrates lettuce and connects to the redis cluster. For more information, please follow other related articles on the PHP Chinese website!