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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:47:02