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

Spring Data Redis 2.4.8连接频繁关闭:如何保持连接存活?

问题描述

使用Java结合Spring Data Redis 2.4.8实现缓存功能时,批量从缓存获取值的场景下,日志中频繁出现Redis连接关闭的记录:

2024-04-02 09:16:14.851 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Fetching Redis Connection from RedisConnectionFactory
2024-04-02 09:16:14.943 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Closing Redis Connection.
2024-04-02 09:16:14.944 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Fetching Redis Connection from RedisConnectionFactory
2024-04-02 09:16:15.035 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Closing Redis Connection.
2024-04-02 09:16:15.036 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Fetching Redis Connection from RedisConnectionFactory
2024-04-02 09:16:15.127 DEBUG 1655457 --- [nio-8080-exec-3] o.s.d.redis.core.RedisConnectionUtils    : Closing Redis Connection.

已在Socket选项中设置keepAlive(true)但无效果,当前配置代码如下:

@Bean
public RedisConnectionFactory redisConnectionFactory() {
    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    redisStandaloneConfiguration.setHostName(redisHost);
    redisStandaloneConfiguration.setPort(redisPort);
    redisStandaloneConfiguration.setPassword(redisPassword);
    redisStandaloneConfiguration.setDatabase(redisDbName);

    LettuceClientConfiguration.LettuceClientConfigurationBuilder builder = LettuceClientConfiguration.builder();
    builder.clientOptions(ClientOptions.builder().autoReconnect(true)
            .socketOptions(SocketOptions.builder().keepAlive(true).build())
            .build()).useSsl();

    return new LettuceConnectionFactory(redisStandaloneConfiguration, builder.build());
}

@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory());
    redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer(objectMapper));
    return redisTemplate;
}

请问如何让Redis连接保持存活?

解决方案

问题核心是未启用连接池,Spring Data Redis默认不配置连接池时,每次操作都会创建新连接并在操作完成后关闭,这就是日志里频繁出现连接关闭的原因。Socket的keepAlive只是TCP层面的保活机制,和连接池的复用不是一回事。

1. 添加Lettuce连接池依赖

如果用Maven,在pom.xml中加入:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

Gradle则添加:

implementation 'org.apache.commons:commons-pool2:2.11.1'

(版本可根据Spring Data Redis 2.4.8的兼容情况调整,2.11.x为稳定版本)

2. 配置Lettuce连接池

修改redisConnectionFactory配置,启用连接池并设置合理参数:

@Bean
public RedisConnectionFactory redisConnectionFactory() {
    RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
    redisStandaloneConfiguration.setHostName(redisHost);
    redisStandaloneConfiguration.setPort(redisPort);
    redisStandaloneConfiguration.setPassword(redisPassword);
    redisStandaloneConfiguration.setDatabase(redisDbName);

    // 配置连接池参数
    GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
    poolConfig.setMaxTotal(20); // 最大连接数
    poolConfig.setMaxIdle(10); // 最大空闲连接数
    poolConfig.setMinIdle(5); // 最小空闲连接数
    poolConfig.setTestOnBorrow(true); // 取连接时测试可用性
    poolConfig.setTestWhileIdle(true); // 空闲时测试连接可用性

    LettuceClientConfiguration.LettuceClientConfigurationBuilder builder = LettuceClientConfiguration.builder();
    builder.clientOptions(ClientOptions.builder().autoReconnect(true)
            .socketOptions(SocketOptions.builder().keepAlive(true).build())
            .build())
            .useSsl()
            .poolConfig(poolConfig); // 启用连接池

    return new LettuceConnectionFactory(redisStandaloneConfiguration, builder.build());
}

3. 优化批量操作的连接复用

批量操作时,用RedisCallback或SessionCallback包裹操作逻辑,让Spring Data Redis复用同一个连接完成所有批量操作,进一步减少连接的获取/归还次数:

List<Object> results = redisTemplate.executePipelined(new RedisCallback<Object>() {
    @Override
    public Object doInRedis(RedisConnection connection) throws DataAccessException {
        StringRedisConnection stringConn = (StringRedisConnection) connection;
        for (String key : keys) {
            stringConn.get(key);
        }
        return null;
    }
});

补充说明

Socket的keepAlive可以保留,它的作用是在TCP连接空闲时发送心跳包,防止中间网络设备(如防火墙)主动断开空闲连接,和连接池的复用是互补的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 18:07:03