英文:
How can we implement client-side load balancing with reactive netty?
问题 {#heading}
我的微服务需要通过TCP连接在2个不同的服务器之间转发请求。使用当前的TCPClient,我们需要提供主机和端口号,这样我就可以连接到一个服务器
TcpClient.create().host(host).port(port)
我看到Netflix Ribbon可以支持TCP,但大多数示例都与HTTP和Eureka相关
我尝试使用Netflix Ribbon,在配置中定义IP地址和端口号,并将tcpClient bean标记为负载平衡。这不起作用。有没有其他解决客户端负载平衡的方法,或者我们应该创建多个TCP客户端并在不同的TCP客户端之间轮换请求?
@Bean
@LoadBalanced
public TcpClient customTcpClient(){
return TcpClient.create();
}
SERVICE:
ribbon:
listOfServers: 123456:1500, 223456:1500
错误:连接被拒绝。没有进一步的信息
注意:在原始实现中,它是带有主机和端口创建的,然后通过自动装配到另一个类来发送请求和接收响应
编辑:
根据这个讨论,可以说只有RestTemplate支持@LoadBalanced,因此我的实现将不起作用吗?
https://stackoverflow.com/questions/39587317/difference-between-ribbonclient-and-loadbalanced#:~:text=TL%3BDR%3A%20%40LoadBalanced%20is,is%20used%20for%20configuration%20purposes.
英文:
My microservice is required to direct requests between 2 different servers via TCP connection. Using the current TCPClient, we are required to provide the host & port numbers which means that I can connect to one server
TcpClient.create().host(host).port(port)
I did see that netflix ribbon can support tcp but most examples are related to http & eureka
I tried using netflix ribbon where i define the ip address and port number under listOfServers in configuration, and annotate tcpClient bean as load balanced. This does not work. Is there any other solution for client side load balancing or should we create multiple tcp clients and rotate the requests between the different tcp clients?
@Bean
@LoadBalanced
public TcpClient customTcpClient(){
return TcpClient.create();
}
SERVICE:
ribbon:
listOfServers: 123456:1500, 223456:1500
Error: Connection refused. No further information
Note: in the original implementation, it is created with host & port, and then autowired into another class to send request and receive response
EDIT:
Based on this discussion, is it right to say that only RestTemplate has support for @LoadBalanced and as such my implementation will not work?
https://stackoverflow.com/questions/39587317/difference-between-ribbonclient-and-loadbalanced#:~:text=TL%3BDR%3A%20%40LoadBalanced%20is,is%20used%20for%20configuration%20purposes.
答案1 {#1}
得分: 0
是的。@LoadBalanced
注解主要设计用于与 RestTemplate 一起进行基于 HTTP 的通信,并不直接支持非 HTTP 协议如 TCP。在您的情况下,您正在使用 TcpClient
进行 TCP 通信,因此无法使用 @LoadBalanced 注解,因为它并不设计用于与 TCP 一起使用。
在这种情况下,您需要自己管理负载平衡。一个方法是手动创建多个具有不同主机和端口组合的 TcpClient 实例,然后在您的代码中管理请求在这些实例之间的分发。这种方法涉及在不同的 TcpClient 实例之间轮换请求,以实现负载平衡。
您可以遵循的方法:
-
创建多个 TcpClient 实例,每个实例具有不同的主机和端口。
-
维护一个集合(例如,列表)来存储这些 TcpClient 实例。
-
在您的应用程序代码中,当您需要建立 TCP 连接时,通过循环遍历 TcpClient 实例的集合来分发负载。
@Configuration public class TcpClientConfig {
@Bean public List<TcpClient> tcpClients() { List<TcpClient> clients = new ArrayList<>(); // 创建并添加具有不同主机和端口的 TcpClient 实例 clients.add(TcpClient.create().host("host1").port(1500)); clients.add(TcpClient.create().host("host2").port(1500)); return clients; }
}
@Service public class TcpLoadBalancer {
@Autowired private List<TcpClient> tcpClients; private AtomicInteger counter = new AtomicInteger(0); public TcpClient getNextTcpClient() { int index = Math.abs(counter.getAndIncrement() % tcpClients.size()); return tcpClients.get(index); } // 使用 getNextTcpClient() 来为每个请求选择一个 TcpClient 实例
}
注意: 我在我的 TcpLoadBalancer 中使用了 AtomicInteger
。AtomicInteger
的主要用途是在多线程环境中,在不使用同步的情况下对整数执行线程安全操作。有关更多信息,请查看此链接:https://stackoverflow.com/a/4818916/12866947
英文:
Q.) Is it right to say that only RestTemplate has support for @LoadBalanced and as such my implementation will not work?
Yes. @LoadBalanced
annotation is primarily designed to work with RestTemplate for HTTP-based communication and doesn't directly support non-HTTP protocols like TCP. In your case you are using a TcpClient
for TCP communication, you won't be able to use the @LoadBalanced annotation because it's not designed to work with TCP.
In this scenario, you'll need to manage the load balancing yourself. One approach could be to manually create multiple instances of your TcpClient with different host and port combinations, and then manage the distribution of requests among these instances in your code. This approach would involve rotating the requests between the different instances of your TcpClient to achieve the load balancing.
Approach you can follow:
- Create multiple instances of TcpClient, each with a different host
and port. - Maintain a collection (e.g., a list) of these TcpClient instances.
- In your application code, when you need to make a TCP connection,
rotate through the collection of TcpClient instances to distribute
the load.
@Configuration
public class TcpClientConfig {
@Bean
public List<TcpClient> tcpClients() {
List<TcpClient> clients = new ArrayList<>();
// Create and add your TcpClient instances with different hosts and ports
clients.add(TcpClient.create().host(&quot;host1&quot;).port(1500));
clients.add(TcpClient.create().host(&quot;host2&quot;).port(1500));
return clients;
`}
`
}
@Service
public class TcpLoadBalancer {
@Autowired
private List&lt;TcpClient&gt; tcpClients;
private AtomicInteger counter = new AtomicInteger(0);
public TcpClient getNextTcpClient() {
int index = Math.abs(counter.getAndIncrement() % tcpClients.size());
return tcpClients.get(index);
}
// Use getNextTcpClient() to select a TcpClient instance for each request
`}
`
Note: I use AtomicInteger
in my TcpLoadBalance. The primary use of AtomicInteger
is when you are in a multithreaded context and you need to perform thread safe operations on an integer without using synchronized. More info checkout this https://stackoverflow.com/a/4818916/12866947