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

如何在Lettuce中覆盖Redis集群节点为Nginx代理地址

问题根因

Lettuce集群模式默认开启拓扑动态刷新功能,会执行CLUSTER NODES命令获取集群所有真实节点的内网地址,后续请求会直接连接这些真实地址,不会走你配置的Nginx代理,就会出现网络不可达超时的问题。

修复步骤

1. 先修正Nginx配置笔误

你的Nginx stream配置里监听端口的指令拼写错误,把lister改为listen,否则Nginx无法正常启动代理:

stream {
    upstream grp1 {
        server node1-1:8762;
        server node1-2:8762;
        server node1-3:8762;
    }
    upstream grp2 {
        server node2-1:8762;
        server node2-2:8762;
        server node2-3:8762;
    }
    server {
        listen 8441; # 修正拼写错误
        proxy_pass grp1;
    }
    server {
        listen 8442; # 修正拼写错误
        proxy_pass grp2;
    }
}

2. 修改Lettuce集群配置,禁用动态节点源+配置地址映射

需要调整ClusterClientOptions的配置,核心是两个参数:

  • dynamicRefreshSources(false):禁止使用动态发现的节点作为拓扑刷新源,始终只用你初始配置的Nginx节点拉取拓扑
  • addressMapper:把拓扑返回的所有真实Redis节点地址,映射为对应的Nginx代理地址,确保所有请求都走代理

修改后的RedisConfig核心代码如下:

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig {

    @Value("${ngnix.ip}")
    private String ngnixIp; // 修正类型拼写:String首字母大写

    @Bean
    LettuceConnectionFactory lettuceConnectionFactory() {
        RedisClusterConfiguration redisCluster = new RedisClusterConfiguration();
        Set<RedisNode> nodes = new HashSet<>();
        nodes.add(new RedisNode(ngnixIp,8441)); // 补全语法括号
        nodes.add(new RedisNode(ngnixIp,8442)); // 补全语法括号
        redisCluster.setClusterNodes(nodes);
        redisCluster.setPassword("mypassword"); 

        // 新增集群拓扑刷新配置
        ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
                // 禁用动态刷新源,始终只用初始配置的Nginx节点拉取拓扑
                .dynamicRefreshSources(false)
                // 按需开启拓扑刷新周期,比如每30秒刷新一次,可选配置
                .enablePeriodicRefresh(Duration.ofSeconds(30))
                .enableAllAdaptiveRefreshTriggers()
                .build();

        // 新增地址映射,把真实节点地址映射为Nginx代理地址
        AddressMapper addressMapper = new AddressMapper() {
            @Override
            public HostAndPort map(HostAndPort hostAndPort) {
                // 判断真实节点所属分片,映射到对应Nginx端口,可按实际规则调整
                String host = hostAndPort.getHost();
                if (host.startsWith("node1-")) {
                    return HostAndPort.of(ngnixIp, 8441);
                } else if (host.startsWith("node2-")) {
                    return HostAndPort.of(ngnixIp, 8442);
                }
                return hostAndPort;
            }
        };

        // 改用集群专用的ClusterClientOptions
        ClusterClientOptions clientOptions = ClusterClientOptions.builder()
                .socketOptions(SocketOptions.builder().connectTimeout(Duration.ofSeconds(10)).build())
                .topologyRefreshOptions(topologyRefreshOptions)
                .addressMapper(addressMapper)
                .build();

        LettuceClientConfiguration clientConfig = LettuceClientConfiguration.builder()
                .commandTimeout(Duration.ofSeconds(5))
                .clientOptions(clientOptions)
                .build();
                
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisCluster, clientConfig);
        lettuceConnectionFactory.setValidateConnection(true);
        lettuceConnectionFactory.setShareNativeConnection(true); // 补全语法分号
        return lettuceConnectionFactory;
    }

    @Bean
    public RedisTemplate<Long, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Long, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        // 建议补充序列化器配置,避免默认JDK序列化产生乱码问题
        return template;
    }
}

3. 可选优化

如果你的Nginx两个代理入口已经做了集群全局请求转发,不需要区分分片,也可以直接把所有真实节点都映射到任意一个Nginx代理端口,Nginx会自动转发到对应节点,不需要判断节点前缀。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:06:03