4

背景

  • 我有一个基于弹簧的网络应用程序。
  • 在本地开发机器上我有 2 个运行相同应用程序的 tomcat 实例 - 这样我测试网络场节点如何相互通信
  • 我使用 Jelastic 云进行应用部署
  • 在 Jelastic 它不是作为网络农场运行,而是使用滚动更新机制(在AppV1运行NodeA并处理用户请求时,我启动AppV2@NodeB,预热并将用户请求重定向到它。目标是让NodeB复制所有会话NodeA

意图

  • 当前发布版本使用基于 NodeJS 的第三个服务器作为节点间 MessageBus 的快捷方式。但最近我发现了 Ignite,并认为减少平台(nodejs)的数量并在 Java 中获取所有内容会很棒。
  • 所以我用 Ignite 消息代替了基于 NodeJS 的消息。Ignite 使用 Spring XML 配置和初始化org.apache.ignite.IgniteSpringBean
  • 在本地运行我的应用程序时,TcpDiscoveryMulticastIpFinder它可以完美运行。NodeA即使没有开始也NodeB开始。当我启动NodeB它时,它顺利加入集群,节点相互连接并完美通信。这里最重要的是我可以随时启动和停止节点,并且使用 Ignite 消息传递进行非阻塞无错误操作。

问题

  • 但是在 Jelastic 上我没有多播,所以我必须明确定义 IP 地址列表(使用TcpDiscoveryVmIpFinder),这没关系 - 我有每个节点的静态主机名。但是现在NodeA开始时它会阻塞,直到它连接到NodeB. 如果NodeB不存在整个应用程序崩溃(部署失败)。

问题是 如何使它在场景中工作

  1. TcpDiscoveryVmIpFinder用来
  2. NodeA开始(虽然NodeB没有开始)
  3. 期望:NodeA正确运行任何时间(当然我不能向遥控器发送消息,因为没有连接遥控器 - 没关系)
  4. 随时NodeB开始
  5. 期望:NodeANodeB相互发现并相互通信(主要用于会话复制和其他消息)
  6. NodeA停止
  7. 期望:NodeB继续正常运行服务用户请求
  8. 现在 switch:NodeA变为NodeB,反之亦然;从第 3 步开始重复
4

2 回答 2

4

您很可能错过了与TcpDiscoveryVmIpFinder. 节点 A 和 B 都必须在 IP finder 的地址列表中包含它们自己的 IP 地址。这在本自述文件部分 [1] 中突出显示。否则,您将陷入与节点 A 必须等待节点 B 加入集群时一样的情况。

为两个节点设置此 IP 查找器,一切都应按要求工作。

                <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
                    <property name="addresses">
                        <list>
                            <value>hodeA_ip_address_or_host_name:47500..47509</value>
                            <value>hodeB_ip_address_or_host_name:47500..47509</value>
                        </list>
                    </property>
                </bean>

[1] https://apacheignite.readme.io/docs/cluster-config#static-ip-based-discovery

于 2016-02-14T17:36:08.133 回答
0

我找到了解决方法(不是解决方案)。如果您知道正确的解决方案 - 请在下面添加答案让我知道。

我对候选人进行了子类化TcpDiscoverySpi和覆盖resolvedAddresses(),以测试他们是否可以访问。

该解决方案并不完美,因为现在如果NodeA没有找到NodeB它永远不会重试 find NodeB。然而,这不是一个炫耀,因为一旦NodeB开始它就会到达NodeA并且他们开始互相交谈。所以有效地滚动更新机制对我有用。

方法isCandidateRespond是快速n-dirty解决方案,很可能会因情况而异。

这是一个代码片段:

public class TcpDiscoverySpiPrecheckingImpl extends TcpDiscoverySpi {
    private Logger log = Logger.getLogger(getClass());

    @Override
    protected Collection<InetSocketAddress> resolvedAddresses() throws IgniteSpiException {
        Collection<InetSocketAddress> candidates = super.resolvedAddresses();
        Collection<InetSocketAddress> approved = new ArrayList<>();
        for (InetSocketAddress candidate : candidates) {
            if (isCandidateRespond(candidate)) {
                approved.add(candidate);
            }
        }
        return approved;
    }

    private boolean isCandidateRespond(InetSocketAddress candidate) {
        if (log.isTraceEnabled()) {
            log.trace("Checking if remote node responds: " + candidate);
        }
        URL url = null;
        try {
            url = new URL("http://" + candidate.getHostName() + "/");
            try (InputStream stream = url.openStream()) {
                return true;
            }
        } catch (Throwable t) {
            log.info("Candidate remote node didn't respond: " + url + ". Reason: " + t.getMessage());
            return false;
        }
    }
}
于 2016-02-14T08:23:34.350 回答