0

0

Springboot2.x集成lettuce连接redis集群报超时异常怎么解决

PHPz

PHPz

发布时间:2023-05-27 19:43:05

|

2554人浏览过

|

来源于亿速云

转载

背景:最近在对一新开发Springboot系统做压测,发现刚开始压测时,可以正常对redis集群进行数据存取,但是暂停几分钟后,接着继续用jmeter进行压测时,发现redis就开始突然疯狂爆出异常提示: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

我急忙检查redis集群,发现集群里的各节点都一切正常,且cpu和内存使用率还不到百分之二十,看着这一切,我突然陷入漫长的沉思,到底是哪里出现问题……百度一番,发现不少人都出现过类似情况的,有人说把超时timeout设置更大一些就可以解决了。我按照这样的解决方法,把超时timeout的值设置到更大后,依然没有解决该超时问题。

其中,springboot操作redis的依赖包是——

  1   2     org.springframework.boot  3     spring-boot-starter-data-redis  4 

集群配置——

  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

点进spring-boot-starter-data-redis进去,发现里面包含了lettuce的依赖:

 Springboot2.x集成lettuce连接redis集群报超时异常怎么解决

springboot1.x默认使用的是jedis,到了Springboot2.x就默认使用了lettuce。我们可以简单验证一下,在redis驱动加载配置类里,输出一下RedisConnectionFactory信息:

  1 @Configuration  2 @AutoConfigureAfter(RedisAutoConfiguration.class)  3 public class Configuration {  4     @Bean  5     public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) {  6         log.info("测试打印驱动类型:"+factory);  7 }

打印输出——

测试打印驱动类型:org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@74ee761e

可见,这里使用正是是lettuce驱动连接,因此,当把它换成以前用的比较多的jedis驱动连接时,就没有再出现这个Command timed out after 6 second(s)问题了。

  1   2     org.springframework.boot  3     spring-boot-starter-data-redis  4       5           6             io.lettuce  7             lettuce-core  8           9      10  11  12     redis.clients 13     jedis 14 

那么问题来了,Springboot2.x是如何默认使用了lettuce,这得去研究下里面的部分代码。我们可以可进入到Springboot2.x自动装配模块的redis部分,其中有一个RedisAutoConfiguration类,其主要作用是对Springboot自动配置连接redis类:

  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

这就意味着使用spring-boot-starter-data-redis依赖时,可自动导入lettuce和jedis两种驱动,按理来说,不会同时存在两种驱动,这样没有太大意义,因此,这里的先后顺序就很重要了,为什么这么说呢?

分别进入到LettuceConnectionConfiguration.class与JedisConnectionConfiguration.class当中,各自展示本文需要涉及到的核心代码:

  1 //LettuceConnectionConfiguration  2 @ConditionalOnClass({RedisClient.class})  3 class LettuceConnectionConfiguration extends RedisConnectionConfiguration {  4    ......省略  5     @Bean  6     @ConditionalOnMissingBean({RedisConnectionFactory.class})  7     LettuceConnectionFactory redisConnectionFactory(ObjectProvider 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 builderCustomizers) throws UnknownHostException { 19         return this.createJedisConnectionFactory(builderCustomizers); 20    } 21 } 22

可见,LettuceConnectionConfiguration.class与JedisConnectionConfiguration.class当中都有一个相同的注解 @ConditionalOnMissingBean({RedisConnectionFactory.class}),这是说,假如RedisConnectionFactory这个bean已经被注册到容器里,那么与它相似的其他Bean就不会再被加载注册,简单点说,对LettuceConnectionConfiguration与JedisConnectionConfiguration各自加上 @ConditionalOnMissingBean({RedisConnectionFactory.class})注解,两者当中只能加载注册其中一个到容器里,另外一个就不会再进行加载注册。

喵记多
喵记多

喵记多 - 自带助理的 AI 笔记

下载

那么,问题就来了,谁会先被注册呢?

这就回到了上面提到的一句,@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})这一句里的先后顺序很关键,LettuceConnectionConfiguration在前面,就意味着,LettuceConnectionConfiguration将会被注册。

可见,Springboot默认是使用lettuce来连接redis的。

当我们引入spring-boot-starter-data-redis依赖包时,其实就相当于引入lettuce包,这时就会使用lettuce驱动,若不想使用该默认的lettuce驱动,直接将lettuce依赖排除即可。

  1   2     org.springframework.boot  3     spring-boot-starter-data-redis  4       5           6             io.lettuce  7             lettuce-core  8           9      10 

然后再引入jedis依赖——

  1   2     redis.clients  3     jedis  4 

这样,在进行RedisAutoConfiguration的导入注解时,因为没有找到lettuce依赖,故而这注解@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})的第二个位置上的JedisConnectionConfiguration就有效了,就可以被注册到容器了,当做springboot操作redis的驱动。

lettuce与jedis两者有什么区别呢?

lettuce:底层是用netty实现,线程安全,默认只有一个实例。

jedis:可直连redis服务端,配合连接池使用,可增加物理连接。

根据异常提示找到出现错误的方法,在下列代码里的LettuceConverters.toBoolean(this.getConnection().zadd(key, score, value))——

  1 public Boolean zAdd(byte[] key, double score, byte[] value) {  2     Assert.notNull(key, "Key must not be null!");  3     Assert.notNull(value, "Value must not be null!");  4   5     try {  6         if (this.isPipelined()) {  7             this.pipeline(this.connection.newLettuceResult(this.getAsyncConnection().zadd(key, score, value), LettuceConverters.longToBoolean()));  8             return null;  9        } else if (this.isQueueing()) { 10             this.transaction(this.connection.newLettuceResult(this.getAsyncConnection().zadd(key, score, value), LettuceConverters.longToBoolean())); 11             return null; 12        } else { 13             return LettuceConverters.toBoolean(this.getConnection().zadd(key, score, value)); 14        } 15    } catch (Exception var6) { 16         throw this.convertLettuceAccessException(var6); 17    } 18 }

LettuceConverters.toBoolean()是将long转为Boolean,正常情况下,this.getConnection().zadd(key, score, value)如果新增成功话,那么返回1,这样LettuceConverters.toBoolean(1)得到的是true,反之,如果新增失败,则返回0,即LettuceConverters.toBoolean(0),还有第三种情况,就是这个this.getConnection().zadd(key, score, value)方法出现异常,什么情况下会出现异常呢?应该是,connection连接失败的时候。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

102

2025.08.06

java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

348

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

27

2025.11.30

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

465

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

12

2025.12.06

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

970

2023.11.02

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

631

2023.11.14

C++ 单元测试与代码质量保障
C++ 单元测试与代码质量保障

本专题系统讲解 C++ 在单元测试与代码质量保障方面的实战方法,包括测试驱动开发理念、Google Test/Google Mock 的使用、测试用例设计、边界条件验证、持续集成中的自动化测试流程,以及常见代码质量问题的发现与修复。通过工程化示例,帮助开发者建立 可测试、可维护、高质量的 C++ 项目体系。

3

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号