【发布时间】:2017-11-11 20:59:15
【问题描述】:
我有两台服务器在负载平衡器后面的 TCP 端口上侦听。负载平衡器可以检测来自客户端的 TCP 连接尝试是否不成功,并在不断开该连接的情况下重试到第二台服务器。我希望能够在不丢失单个客户端集合的情况下关闭这两个服务器中的任何一个进行维护。
我的服务器使用此代码来处理客户端请求:
ServerSocketFactory ssf = ...
ServerSocket serverSocket = ssf.createServerSocket(60000);
try {
while (true) {
Socket socket = serverSocket.accept();
...// Do the processing
}
} catch (IOException e) {
...
}
...
我最初的想法是添加一个布尔值,它将在应用程序关闭时设置,并在等待所有现有连接被处理和关闭时阻止新的serverSocket.accept() 调用。但是,甚至在serverSocket.accept() 调用之前就已经建立了新的连接。如果我在该调用之前放置断点,这就是我在 Wireshark 中看到的内容。
问题是,只要我打电话给serverSocket.close(),所有这样的客户端连接都会被丢弃。我想要实现的是某种方式告诉 ServerSocket 停止接受所有新连接(即只为新连接发送 RST 或让它们超时),因此负载均衡器可以将它们重新路由到另一台服务器,但同时不会丢弃任何已建立的连接。
编辑:我正在寻找一些自动化解决方案,它不需要我每次想要更新应用程序时都更改任何负载平衡器或操作系统设置。
【问题讨论】:
-
我相信它是负载均衡器的功能,它检测哪些服务器可用于服务并将新连接转发到该服务器。我不会让你的 Socket 代码更复杂,因为它不是它的功能。查看您的负载均衡器运行状况检查和路由配置。如果您将其中一个服务器 ip 从平衡器路由表中取出,那么新的连接将采用另一种方式。
-
是的,这是负载均衡器检测可用服务器的功能,它完成了它的工作。它检测连接是否未建立(重置或超时)并将该连接转发到另一台服务器。问题是我的服务器一直在接受新连接,即使我不希望它接受,在我打电话给
serverSocket.close()之前。一旦我调用它所有已经建立的连接,serverSocket.accept()没有被调用,但都被丢弃了。在这种情况下,负载均衡器无法帮助我,因为它认为这些连接已建立并假定服务器可以处理它们。 -
这取决于您的负载均衡器的配置方式。我使用的负载均衡器(F5)有一个健康检查配置。我们公开了一个 servlet-endpoint 供 LB 监控。如果我们让这个服务不可用,LB 会认为服务器宕机,不会在那里路由新的流量。
-
我也使用 F5,它确实有健康检查。我使用Reselect Tries option and Inband monitor,所以如果连接失败,它总是会重试连接到另一台服务器。但它仍然没有解决上述问题,因为这些连接只有在它们已经建立后才会失败。使用一些“每隔 n 秒检查一次”健康监视器而不是 Inband 会更糟糕,因为在我关闭服务器和 F5 发送下一个健康检查请求并检测到它已关闭之间总是有一个时间范围。
-
这是一个非常有趣的话题。你应该阅读veithen.github.io/2014/01/01/…。似乎没有办法做你想做的事,因为在 java 中将应用程序级别的 ack 队列设置为零是不可能的(而且无论如何也没有多大意义)你真的应该按照其他人的建议去做并实施另一个健康检查
标签: java sockets tcp high-availability