Spring Boot集成Redis:Lettuce未创建连接池问题排查
问题描述
我正在使用spring-boot-starter-cache进行Redis交互,已配置Lettuce连接池相关参数且设置了shareNativeConnection=false,但连接池始终未初始化。以下是相关配置与信息:
初始化配置代码
@Autowired private LettuceConfigProperties lettuceConfigProperties; @Bean public RedisConnectionFactory redisConnectionFactory() { RedisClusterConfiguration clusterConfiguration = new RedisClusterConfiguration(); for (RedisNodeDetails nodeDetails : lettuceConfigProperties.getServers()) { if (nodeDetails.getPort() == null) { nodeDetails.setPort(lettuceConfigProperties.getDefaultPort()); } clusterConfiguration.addClusterNode(new RedisNode(nodeDetails.getHost(), nodeDetails.getPort())); } clusterConfiguration.setPassword(lettuceConfigProperties.getPassword()); if (clusterConfiguration.getClusterNodes().size() == 1) { RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration(); standaloneConfiguration.setPassword(lettuceConfigProperties.getPassword()); standaloneConfiguration.setHostName(lettuceConfigProperties.getServers().get(0).getHost()); standaloneConfiguration.setPort(lettuceConfigProperties.getServers().get(0).getPort()); var lettuceConnectionFactory = new LettuceConnectionFactory(standaloneConfiguration, createLettuceClientConfiguration()); lettuceConnectionFactory.setShareNativeConnection(false); return lettuceConnectionFactory; } var lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfiguration, createLettuceClientConfiguration()); lettuceConnectionFactory.setShareNativeConnection(false); return lettuceConnectionFactory; } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); template.afterPropertiesSet(); return template; } @Bean public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() .disableCachingNullValues() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class))); log.info("[LETTUCE] Initializing....."); return RedisCacheManager.builder(connectionFactory) .cacheDefaults(cacheConfiguration) .build(); } @Bean @Primary public LettuceClientConfiguration createLettuceClientConfiguration() { return LettucePoolingClientConfiguration.builder() .poolConfig(createPoolConfig()) .clientOptions(clientOptions()) .clientResources(lettuceClientResources()) .commandTimeout(Duration.ofMillis(lettuceConfigProperties.getConnections().getCommandTimeout())) .build(); } @Bean public ClientOptions clientOptions() { return ClientOptions.builder() .autoReconnect(true) .requestQueueSize(lettuceConfigProperties.getMaxRequestQueueSize()) .socketOptions(SocketOptions.builder() .connectTimeout(Duration.ofMillis(lettuceConfigProperties.getConnections().getSocketTimeout())) .keepAlive(SocketOptions.KeepAliveOptions.builder() .enable().idle(Duration.ofMillis(lettuceConfigProperties.getConnections().getKeepAliveIdleTimeout())).build()) .tcpNoDelay(true) .build()) .timeoutOptions( TimeoutOptions.builder() .timeoutCommands() .connectionTimeout() .build() ) .build(); } @Bean(destroyMethod = "shutdown") public ClientResources lettuceClientResources() { return DefaultClientResources.create(); } private GenericObjectPoolConfig<?> createPoolConfig() { GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxIdle(lettuceConfigProperties.getConnections().getMaxIdle()); poolConfig.setMaxTotal(lettuceConfigProperties.getConnections().getMax()); poolConfig.setMinIdle(lettuceConfigProperties.getConnections().getMinIdle()); poolConfig.setMaxWait(Duration.ofMillis(lettuceConfigProperties.getConnections().getMaxWait())); poolConfig.setMinEvictableIdleTime(Duration.ofMillis(lettuceConfigProperties.getConnections().getMinIdleEvictTime())); poolConfig.setTestWhileIdle(true); poolConfig.setTestOnBorrow(false); poolConfig.setTestOnReturn(false); poolConfig.setTestOnCreate(false); poolConfig.setLifo(true); poolConfig.setBlockWhenExhausted(true); return poolConfig; }
活跃线程列表
"lettuce-eventExecutorLoop-1-1", "lettuce-timer-3-1", "lettuce-nioEventLoop-4-1", "lettuce-eventExecutorLoop-1-2"
连接池YAML配置
default_port: 6379 password: ******** maxRequestQueueSize: 200000 servers: - host: *.*.*.* port: 6379 connections: max: 20 minIdle: 5 maxIdle: 10 commandTimeout : 1000 socketTimeout: 1000 keepAliveIdleTimeout: 60000 maxWait: 5000 minIdleEvictTime: 60000
已确认LettuceClientConfiguration初始化参数正确,但连接池仍未生效,请求排查原因。
可能的原因与解决建议
1. 缺失连接池依赖
Lettuce连接池依赖commons-pool2组件,Spring Boot的spring-boot-starter-data-redis默认不会自动引入该依赖。需在构建文件中手动添加:
Maven
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
Gradle
implementation 'org.apache.commons:commons-pool2'
若未添加该依赖,LettucePoolingClientConfiguration会直接失效,连接池逻辑不会被初始化。
2. 连接池懒加载特性
Lettuce连接池采用懒加载模式,仅当实际发起Redis请求时才会创建并初始化连接池。可执行一次Redis操作(如redisTemplate.opsForValue().set("test", "value"))后,再检查线程或连接状态,确认连接池是否已初始化。
3. 配置映射验证
检查LettuceConfigProperties类中connections属性的字段是否与YAML配置正确映射:
- YAML中的
max需对应GenericObjectPoolConfig的maxTotal属性,确保配置类中getMax()方法正确绑定该参数; - 其他属性如
minIdle、maxIdle等也需保证字段名与YAML配置一致,避免因绑定失败导致连接池参数未生效。
4. Bean优先级冲突
虽然createLettuceClientConfiguration添加了@Primary注解,但需确认是否存在其他LettuceClientConfiguration类型的Bean,导致当前配置被覆盖。可通过打印Bean名称或查看Spring上下文Bean列表,验证该配置是否被正确加载。
5. 日志排查
开启Lettuce与连接池的DEBUG日志,查看初始化细节:
- 日志包路径:
io.lettuce.core(Lettuce核心)、org.apache.commons.pool2(连接池); - 通过日志可确认连接池是否被初始化,以及是否存在参数绑定错误、连接创建失败等异常信息。
内容的提问来源于stack exchange,提问作者Ajay Pilaniya

