我有一个Spring Boot应用程序,其中应用程序的每个实例都是集群中的节点,并且每个节点都需要能够与集群中的其他节点通信以共享信息。出于性能原因,这不可能通过HTTP发生,尽管群集中每个节点的初始联系是通过HTTP调用。
要进行初始HTTP调用,实例需要能够获取正在运行其他实例的端口,以便它们可以相互注册。这意味着每个节点都需要知道其Tomcat实例正在使用的端口。
如果我部署包含嵌入式Tomcat实例的WAR文件,这样可以正常工作。我为EmbeddedServletContainerInitializedEvent注册一个ApplicationListener,并从EmbbededServletContainer获取端口。
当我将WAR文件部署到已经运行的Tomcat实例时出现问题。我无法找到确定运行Tomcat实例的端口的方法,并且由于Tomcat实例已在运行,因此上述事件不再触发。
有人知道如何找出正在使用的端口吗?
答案 0 :(得分:0)
简单地说:你不能。 webapp并不知道它正在运行的容器。事实上,Tomcat可以有多个连接器并且可以在多个端口中监听......
答案 1 :(得分:0)
我知道这并没有具体回答您的问题,但是有更简单的方法来实现群集节点发现。
作为一个明显的例子,我建议考虑使用共享数据库。这已由JGroups实现为JDBC_PING。
答案 2 :(得分:0)
经过一些工作后,以下问题的代码解释了这个问题的解决方法(谢谢Ann Addicks让我再看一遍): org.apache.catalina.ServerFactory.getServer() equivalent in Tomcat 7
此代码对SpringBoot应用程序中调用它的位置非常敏感。由于ApplicationPreparedEvent,我的初始化代码在SpringBoot应用程序启动时很早就运行了。当我第一次尝试这段代码时,我让它运行得如此早以至于代码会失败。我不太清楚为什么,但我不需要提前做这个初始化,所以我在启动时稍稍调用了这段代码并解决了问题。
此代码需要注意以下几点:
正如joshiste指出的那样,这只会让我找到一个Tomcat端口,但这就是我需要的全部内容。
正如Alex指出的那样,群集应该由一些后端持久性存储来处理,我已经这样做了。问题在于,有时节点需要调用另一个节点,因为其他节点在集群中具有密切的知识。这是一种不寻常的情况,对整个集群的完整性至关重要。
以下方法显示了我最终如何使用它:
private int getTomcatContainerPort() throws MalformedObjectNameException, AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
int serverPort = 0;
MBeanServer mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
ObjectName name = new ObjectName("Catalina", "type", "Server");
Server server = (Server) mBeanServer.getAttribute(name, "managedResource");
Service[] services = server.findServices();
for (Service service : services) {
for (Connector connector : service.findConnectors()) {
ProtocolHandler protocolHandler = connector.getProtocolHandler();
if (protocolHandler instanceof Http11Protocol
|| protocolHandler instanceof Http11AprProtocol
|| protocolHandler instanceof Http11NioProtocol) {
serverPort = connector.getPort();
break;
}
}
}
return serverPort;
}