You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot 2.2.9连接Redis7.0.8集群报RedisConnectionException求助

Redis 7.0.8集群与SpringBoot 2.2.9.RELEASE连接失败问题排查

问题现象

本地CentOS7虚拟机部署Redis 7.0.8集群,SpringBoot 2.2.9.RELEASE连接时持续报错;单机Redis可正常连接,虚拟机内集群操作正常,主机与虚拟机网络互通且防火墙未开启。

错误日志

2023-03-01 20:09:31.523 ERROR 32280 --- [nio-9913-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Redis connection failed; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to [RedisURI [host='192.168.129.XXX', port=7010], RedisURI [host='192.168.129.XXX', port=7020], RedisURI [host='192.168.129.XXX', port=7030], RedisURI [host='192.168.129.XXX', port=7011], RedisURI [host='192.168.129.XXX', port=7021], RedisURI [host='192.168.129.XXX', port=7031]]] with root cause

java.lang.UnsupportedOperationException: null
    at java.util.AbstractList.add(AbstractList.java:148) ~[na:1.8.0_151-1-redhat]
    at java.util.AbstractList.add(AbstractList.java:108) ~[na:1.8.0_151-1-redhat]
    at io.lettuce.core.output.ArrayOutput.set(ArrayOutput.java:54) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.RedisStateMachine.safeSet(RedisStateMachine.java:358) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.RedisStateMachine.decode(RedisStateMachine.java:139) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:716) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.CommandHandler.decode0(CommandHandler.java:680) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:675) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:596) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:565) ~[lettuce-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151-1-redhat]

环境验证

虚拟机内Redis集群可正常操作:

[root@localhost ~]# redis-cli -c -p 7010
127.0.0.1:7010> get boo
-> Redirected to slot [13142] located at 192.168.129.XXX:7030
"for"
192.168.129.XXX:7030> set hello world
-> Redirected to slot [866] located at 192.168.129.XXX:7010
OK
192.168.129.XXX:7010> get hello
"world"
192.168.129.XXX:7010>

当前配置

SpringBoot配置类

@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {
    List<String> nodes;
    public List<String> getNodes() {
        return nodes;
    }
    public void setNodes(List<String> nodes) {
        this.nodes = nodes;
    }
}


@Configuration
public class RedisClusterConfig {

    @Autowired
    ClusterConfigurationProperties clusterProperties;

    @Bean
    public RedisConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory(
                new RedisClusterConfiguration(clusterProperties.getNodes()));
    }

    @Bean
    public RedisTemplate<String, byte[]> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, byte[]> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

application.properties

spring.redis.cluster.nodes[0]=192.168.129.XXX:7010
spring.redis.cluster.nodes[1]=192.168.129.XXX:7020
spring.redis.cluster.nodes[2]=192.168.129.XXX:7030
spring.redis.cluster.nodes[3]=192.168.129.XXX:7011
spring.redis.cluster.nodes[4]=192.168.129.XXX:7021
spring.redis.cluster.nodes[5]=192.168.129.XXX:7031
spring.redis.password=
spring.redis.cluster.max-redirects=3
spring.redis.timeout=60000ms
spring.redis.lettuce.pool.max-active=32
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=16
spring.redis.lettuce.pool.min-idle=8

Redis集群节点配置(redis.conf)

port 7010
cluster-enabled yes
cluster-config-file nodes-7010.conf
cluster-node-timeout 5000
appendonly yes
daemonize yes
#requirepass redis-123456
loglevel warning
logfile /root/Tools/redis-cluster/7010/redis_7010.log
#bind 0.0.0.0
protected-mode no

解决方案

原因分析

报错栈显示java.lang.UnsupportedOperationException发生在AbstractList.add方法,核心问题是Lettuce版本与Redis 7.0.8不兼容:Redis 7.x新增了集群相关的响应格式,而当前使用的Lettuce 5.2.2.RELEASE在解析这些响应时,会尝试向不可修改的列表添加元素,导致抛出异常。

修复步骤

  1. 升级Lettuce版本
    将Lettuce版本升级至5.3.7.RELEASE及以上(该版本已修复Redis 7.x集群的兼容性问题):

    • Maven项目在pom.xml中添加依赖覆盖:
      <dependency>
          <groupId>io.lettuce</groupId>
          <artifactId>lettuce-core</artifactId>
          <version>5.3.7.RELEASE</version>
      </dependency>
      
    • Gradle项目添加:
      implementation 'io.lettuce:lettuce-core:5.3.7.RELEASE'
      
  2. 验证集群节点对外暴露IP
    检查Redis集群节点生成的配置文件,确保节点对外暴露的是虚拟机IP而非127.0.0.1:

    cat /root/Tools/redis-cluster/7010/nodes-7010.conf | grep "myself"
    

    如果显示为127.0.0.1,需停止集群,修改每个节点的redis.conf添加bind 192.168.129.XXX 127.0.0.1,然后重新创建集群:

    redis-cli --cluster create 192.168.129.XXX:7010 192.168.129.XXX:7020 192.168.129.XXX:7030 192.168.129.XXX:7011 192.168.129.XXX:7021 192.168.129.XXX:7031 --cluster-replicas 1
    
  3. 简化配置(可选)
    无需自定义配置类,直接使用SpringBoot自动配置:
    修改application.properties节点配置为逗号分隔格式:

    spring.redis.cluster.nodes=192.168.129.XXX:7010,192.168.129.XXX:7020,192.168.129.XXX:7030,192.168.129.XXX:7011,192.168.129.XXX:7021,192.168.129.XXX:7031
    

    同时删除自定义的ClusterConfigurationProperties和RedisClusterConfig,SpringBoot会自动创建适配的连接工厂。

验证

重启SpringBoot应用,测试Redis集群操作,确认连接正常。

内容的提问来源于stack exchange,提问作者Neil660

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:37:05