Redis 连接异常问题记录

问题描述

使用 Lettuce 客户端,Redis服务出现超时错误。

错误提示:RedisCommandTimedoutException

错误原因

Lettuce 断开链接问题,在连不上

官方论坛:https://github.com/lettuce-io/lettuce-core/issues/2082

官方论坛: https://github.com/lettuce-io/lettuce-core/issues/2082#issuecomment-1702782618

以下是在 Spring Boot 项目中解决 Lettuce 客户端连接断开的问题一个解决方案

一、依赖管理(确保版本兼容性)

  1. 升级 Lettuce 版本(推荐 6.2.7+ 或最新稳定版):
    pom.xml 中显式指定 Lettuce 版本(Spring Boot 2.4+ 默认支持 Lettuce 6.x):
    <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>io.lettuce</groupId>
        <artifactId>lettuce-core</artifactId>
        <version>6.2.7.RELEASE</version> <!-- 使用最新版本 -->
    </dependency>
    

二、基础配置(application.yml

在配置文件中设置 Redis 连接参数和 Lettuce 的默认行为:

spring:
  redis:
    host: your-redis-host
    port: 6379
    password: your-password
    timeout: 2000ms  # 命令执行超时时间(避免线程阻塞)
    lettuce:
      pool:
        enabled: true  # 启用连接池(需添加 commons-pool2 依赖)
        max-active: 8
        max-idle: 4
        min-idle: 1
        max-wait: 1000ms
      shutdown-timeout: 100ms  # 关闭连接等待时间

三、自定义 Lettuce 配置类

通过 LettuceClientConfigurationBuilder 启用高级配置(如连接验证、TCP 保活等):

@Configuration
public class LettuceConfig {

    @Bean
    public LettuceConnectionFactory redisConnectionFactory(
        RedisProperties redisProperties,
        ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers
    ) {
        // 构建 Lettuce 客户端配置
        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
            .commandTimeout(redisProperties.getTimeout())
            .clientOptions(clientOptions())  // 核心配置
            .build();

        // 创建连接工厂
        RedisStandaloneConfiguration serverConfig = new RedisStandaloneConfiguration(
            redisProperties.getHost(), redisProperties.getPort());
        serverConfig.setPassword(redisProperties.getPassword());
        return new LettuceConnectionFactory(serverConfig, clientConfig);
    }

    // 配置 ClientOptions 和 SocketOptions
    private ClientOptions clientOptions() {
        SocketOptions socketOptions = SocketOptions.builder()
            .keepAlive(KeepAliveOptions.builder()
                .enable()  // 启用 TCP KeepAlive
                .idle(Duration.ofSeconds(60))  // 空闲检测间隔
                .interval(Duration.ofSeconds(20))  // 保活探测间隔
                .count(3)  // 探测失败次数
                .build())
            .tcpUserTimeout(TcpUserTimeoutOptions.builder()
                .enable()  // 启用 TCP_USER_TIMEOUT
                .tcpUserTimeout(Duration.ofSeconds(30))  // 超时阈值(需小于服务端超时配置)
                .build())
            .build();

        return ClientOptions.builder()
            .autoReconnect(true)  // 自动重连
            .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS)  // 连接断开时拒绝命令
            .socketOptions(socketOptions)
            .build();
    }
}

四、强制验证连接有效性

在业务代码中捕获异常并重置连接(例如在 @Service 类中):

@Service
public class RedisService {

    @Autowired
    private LettuceConnectionFactory lettuceConnectionFactory;

    public String getValue(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (RedisCommandTimeoutException | RedisConnectionFailureException ex) {
            // 强制重置连接池
            lettuceConnectionFactory.resetConnection();
            throw ex;  // 可在此处添加重试逻辑
        }
    }
}

五、操作系统和 Redis 服务端优化

  1. 调整 Linux TCP 参数(在服务器执行):

    echo 5 > /proc/sys/net/ipv4/tcp_retries2  # 减少 TCP 重试次数
    echo 60 > /proc/sys/net/ipv4/tcp_keepalive_time  # 缩短保活检测间隔
    
  2. Redis 服务端配置redis.conf):

    timeout 300  # 服务端主动关闭空闲连接(单位:秒)
    tcp-keepalive 60  # 与服务端保活配置一致
    

六、备选方案:切换至 Jedis

若问题仍无法解决,可排除 Lettuce 并引入 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>

application.yml 中启用 Jedis 连接池:

spring:
  redis:
    client-type: jedis  # 显式指定使用 Jedis

七、最佳实践总结

措施配置位置效果
升级 Lettuce 版本pom.xml支持 TCP_USER_TIMEOUT 等新特性
启用连接验证与保活自定义 LettuceConfig主动检测失效连接,减少超时概率
调整 TCP 重试次数操作系统参数缩短底层重试延迟
异常时重置连接业务代码异常处理快速恢复可用连接
启用连接池并监控application.yml避免频繁创建连接,提升资源利用率

验证配置是否生效

  1. 日志观察
    在日志中搜索 LettuceConnection 相关输出,确认连接重置和保活行为。

  2. 网络抓包
    使用 tcpdump 或 Wireshark 观察 TCP KeepAlive 包是否按预期发送:

    tcpdump -i eth0 'tcp port 6379 and (tcp[13] & 8!=0)'  # 检测保活包
    
  3. 模拟断网测试
    手动断开 Redis 服务端网络,观察客户端重连耗时是否符合配置的 tcpUserTimeout(如30秒)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值