Redis command timed out nested exception is io.lettuce.core.RedisCommandTimeoutException
发布于 2022-09-07    9,489 次阅读
报错如下: ERROR org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 500 millisecond(s) at org...

报错如下:

ERROR org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException: Command timed out after 500 millisecond(s)
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:70)
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)
	at org.springframework.data.redis.PassThroughExceptionTranslationStrategy.translate(PassThroughExceptionTranslationStrategy.java:44)
	at org.springframework.data.redis.FallbackExceptionTranslationStrategy.translate(FallbackExceptionTranslationStrategy.java:42)
	at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:268)
	at org.springframework.data.redis.connection.lettuce.LettuceListCommands.convertLettuceAccessException(LettuceListCommands.java:490)
	at org.springframework.data.redis.connection.lettuce.LettuceListCommands.lLen(LettuceListCommands.java:159)
	at org.springframework.data.redis.connection.DefaultedRedisConnection.lLen(DefaultedRedisConnection.java:465)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	****
Caused by: io.lettuce.core.RedisCommandTimeoutException: Command timed out after 500 millisecond(s)
	at io.lettuce.core.ExceptionFactory.createTimeoutException(ExceptionFactory.java:51)
	at io.lettuce.core.LettuceFutures.awaitOrCancel(LettuceFutures.java:114)
	at io.lettuce.core.FutureSyncInvocationHandler.handleInvocation(FutureSyncInvocationHandler.java:69)
	at io.lettuce.core.internal.AbstractInvocationHandler.invoke(AbstractInvocationHandler.java:80)
	at com.sun.proxy.$Proxy196.llen(Unknown Source)
	at org.springframework.data.redis.connection.lettuce.LettuceListCommands.lLen(LettuceListCommands.java:157)
	... 134 more

原因分析:这个情况是我在将SpringBoot从1.X升级到2.X的时候产生的问题,所以大致可以猜到是版本问题。

解决办法:

  • 设置超时时间
redis:
    port: 6379
    jedis:
      pool:
        max-active: 50
        max-wait: 5000
        max-idle: 50
        min-idle: 0
    timeout: 500
    host: 47.100.21.110

这种方法无效,解决不了这个问题,我从0改到500还是报错。但是网上绝大多数都是这种方式,实际上我刚更改过来的时候有效过一阵,之后就又不行了。

  • 更改依赖
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在SpringBoot 1.X版本的jar包依赖中,点击进去依赖项如下:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.data</groupId>
		<artifactId>spring-data-redis</artifactId>
	</dependency>
	<dependency>
		<groupId>redis.clients</groupId>
		<artifactId>jedis</artifactId>
	</dependency>
</dependencies>

升级到SpringBoot 2.X版本之后依赖如下:

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>2.1.2.RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>2.1.4.RELEASE</version>
      <scope>compile</scope>
      <exclusions>
        <exclusion>
          <artifactId>jcl-over-slf4j</artifactId>
          <groupId>org.slf4j</groupId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>io.lettuce</groupId>
      <artifactId>lettuce-core</artifactId>
      <version>5.1.3.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

可以看到变化是从jedis依赖变成了lettuce-core依赖,而上面的报错io.lettuce.core.RedisCommandTimeoutException也是lettuce-core的异常,所以我的解决方式是先将依赖换回jedis:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
</dependency>

如上,配置文件不变,Redis连接成功,不再报错。

补充(深入一点点,个人理解,勿喷)

因为上文是我在版本升级的过程中遇到的,所以当时为了稳定还是继续使用的jedis连接池,但是实际上升级之后应该转向lettuce连接池,毕竟lettuce更好。
修改依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 如果使用Lettuce作为连接池,需要引入commons-pool2包,否则会报错bean注入失败 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

修改配置文件

spring:
  redis: 
    port: 6379
    lettuce:
      pool:
        max-active: 500
        max-wait: 500
        max-idle: 500
        min-idle: 0
    timeout: 500
    host: 100.10.10.10
    password: password
分析
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ 
    LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration { 
   

首先是加载顺序。
在这里插入图片描述
同时我在@ConditionalOnClass(RedisClient.class)@ConditionalOnClass({ GenericObjectPool.class, JedisConnection.class, Jedis.class })类里面打断点,发现仅RedisClient执行了,这让我明白为啥LettuceConnectionConfiguration配置生效,但是我没明白RedisClient为啥执行。。。。项目刚启动就进来这里,再上一层我实在没找到,希望哪位研究到这里可以给个反馈。

我想要抛出LettuceConnectionConfiguration配置时失效,有异常信息。

此文仅做记录,尚未分析原因,后续补充。