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

如何为Reactive Netty的TCP客户端实现客户端侧负载均衡?

TCP客户端负载均衡问题

我的微服务需要通过TCP连接在两台不同服务器间转发请求。当前使用TcpClient时必须指定主机和端口,仅能连接单一服务器:

TcpClient.create().host(host).port(port)

我了解到Netflix Ribbon支持TCP,但多数示例围绕HTTP和Eureka展开。

我尝试在配置的listOfServers中定义IP与端口,并为TcpClient Bean添加@LoadBalanced注解,但方案无效。是否有其他客户端侧负载均衡方案?或需创建多个TcpClient并轮询请求?

相关代码

@Bean
@LoadBalanced
public TcpClient customTcpClient(){
  return TcpClient.create();
}

配置信息

SERVICE:
  ribbon:
    listOfServers: 123456:1500, 223456:1500

报错信息

Connection refused. No further information

备注:原实现中,TcpClient指定主机端口创建后,通过@Autowired注入到其他类收发请求。

补充疑问:是否仅RestTemplate支持@LoadBalanced,导致我的实现无效?


解决方案

1. 明确@LoadBalanced的适用范围

没错,@LoadBalanced注解仅对Spring提供的RestTemplate、WebClient等HTTP客户端生效,它是Spring Cloud为HTTP场景封装的负载均衡增强,对原生TcpClient没有作用,这就是配置无效的核心原因。

2. 基于Ribbon实现TCP负载均衡的正确方式

Ribbon本身支持TCP场景,但需要手动整合,步骤如下:

  • 步骤1:确保项目引入Ribbon核心依赖
  • 步骤2:创建Ribbon负载均衡器实例
    @Bean
    public ILoadBalancer ribbonLoadBalancer() {
        BaseLoadBalancer loadBalancer = new BaseLoadBalancer();
        // 从配置读取服务器列表,也可通过配置类绑定读取
        List<Server> servers = Arrays.stream("123456:1500,223456:1500".split(","))
                .map(s -> {
                    String[] parts = s.split(":");
                    return new Server(parts[0], Integer.parseInt(parts[1]));
                })
                .collect(Collectors.toList());
        loadBalancer.setServersList(servers);
        // 设置负载均衡规则,比如轮询
        loadBalancer.setRule(new RoundRobinRule());
        return loadBalancer;
    }
    
  • 步骤3:封装负载均衡逻辑的TCP客户端服务
    @Service
    public class LoadBalancedTcpService {
        @Autowired
        private ILoadBalancer loadBalancer;
    
        public TcpClient getBalancedTcpClient() {
            Server targetServer = loadBalancer.chooseServer(null);
            return TcpClient.create().host(targetServer.getHost()).port(targetServer.getPort());
        }
    }
    
    业务类中注入该服务,调用getBalancedTcpClient()即可获取带负载均衡的TCP客户端。

3. 轻量替代:手动实现轮询逻辑

如果不想引入Ribbon,可手动维护服务器列表实现简单轮询:

@Component
public class RoundRobinTcpProvider {
    private final List<Server> servers = Arrays.asList(
            new Server("123456", 1500),
            new Server("223456", 1500)
    );
    private final AtomicInteger index = new AtomicInteger(0);

    public TcpClient getTcpClient() {
        int currentIdx = index.getAndIncrement() % servers.size();
        Server target = servers.get(currentIdx);
        return TcpClient.create().host(target.getHost()).port(target.getPort());
    }
}

这种方式适合简单场景,但缺少Ribbon的服务健康检查、重试等高级特性。

4. 关键排查点

先验证单台服务器的TCP连接是否正常——Connection refused大概率是目标端口未开放、防火墙拦截导致,和负载均衡配置无关。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:30:23