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
相关产品推荐
相关产品推荐

