EAP 7 JMS 集群不同步。节点关闭时计划的 JMS 消息被阻止

EAP 7 JMS cluster not in sync. Scheduled JMS message blocked when node is down

我正在以独立模式设置 EAP 7 集群。我按照 this tutorial 设置了我的集群。

然后我开始用一个简单的 JMS 应用程序测试 JMS 系统。每次发送 JMS 消息时,我都会观察到 JMS 消息计数仅在一个节点(而不是视频中显示的两个节点)中更新。发送的消息总数等于来自两个节点的计数之和。

但是,由于节点是集群的,我希望 JMS 统计信息是同步的(如视频所示),因此两个节点都应该显示集群中收到的消息总数,而不是仅显示部分消息他们。

另外,在发送定时消息时,如果持有消息的节点挂掉,则消息会被阻塞,直到挂掉的节点重启。这绝对是不可接受的,因为我希望预定消息由另一个 (运行) 节点传递。

所有测试都使用默认的 standalone-full-ha.xml

以下是重现问题的所有步骤:

环境设置

  1. 下载eap7.1/7.2或wildfly12/14解压到一个目录
  2. 将目录重命名为 my-dir-node1
  3. 将 your-dir-node1 复制到 my-dir-node2
  4. 更新配置
    1. 转到my-dir-node1/standalone并将standalone-full-ha.xml复制到standalone-full-ha-test.xml
    2. 编辑my-dir-node1/standalone/standalone-full-ha-test.xml
    3. 将 name="node1" 添加到根元素:<server xmlns="urn:jboss:domain:5.0" name="node1">
    4. 搜索 <cluster password="${jboss.messaging.cluster.password:CHANGE ME!!}"/> 并将其替换为 <cluster password="${jboss.messaging.cluster.password:mypassword}"/>
    5. <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
    6. 之后添加<jms-queue name="JMSTest" entries="java:/jms/queue/test"/>
    7. 转到my-dir-node2/standalone并重复上述步骤。确保将其命名为服务器 "node2" 而不是 "node1"

通过将 test-jms.war 复制到 my-dir-node1/standalone/deploy 和 your-dir-node2/standalone/deploy

来部署测试应用

我的测试应用程序的内容

<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.jms.*" %>
<%@ page import="java.util.logging.Logger" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<%

    Logger logger = Logger.getLogger("JMSSender");
    InitialContext initialContext = new InitialContext();
    ConnectionFactory factory = (ConnectionFactory) initialContext.lookup("ConnectionFactory");
    Destination destination = (Destination)initialContext.lookup("java:/jms/queue/test");
    Connection connection = factory.createConnection();
    Session session1 = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    MessageProducer messageProducer = session1.createProducer(destination);

    String body = request.getParameter("message");

    if (body == null)
        body = "Hello World!";

    TextMessage message = session1.createTextMessage(body);

    String delay = request.getParameter("delay");

    if (delay != null)
        message.setJMSDeliveryTime(System.currentTimeMillis() + Integer.parseInt(delay));

    messageProducer.send(message);

    logger.info("Send message: " + body);
%>
<html>
  <head>
    <title>Test JMS Sender</title>
  </head>
  <body>
  <h1>Message</h1>
  <p><strong><%=body%></strong></p>
  <p>Add ?message=xxx to the url to change the message.</p>
  <p>Add ?delay=xxx to the url to schedule a delivery at a later time. The unit of delay is in millisecond. ie: 1 second = 1000 </p>
  </body>
</html>

JMS 接收方:

import org.apache.log4j.Logger;

import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@MessageDriven(mappedName = "testQueue", activationConfig =  {
        @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")
        , @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
        , @ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/jms/queue/test")
})
public class JMSReceiver implements MessageListener {

    // Logger for the class
    private static Logger logger = Logger.getLogger(JMSReceiver.class.getName());

    @Override
    public void onMessage(Message message) {
        TextMessage t = (TextMessage) message;
        try {
            logger.info(t.getText());
        } catch (JMSException e) {
            logger.info(e.getMessage());
        }
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

您对 EAP 中的消息集群(以及您链接的视频)的理解不正确。如果您将 1 消息发送到 EAP 中的消息集群,集群中只有 1 节点有该消息。消息不会在集群中的所有节点之间复制。集群中每个节点的 JMS 统计信息 不一定 同步。

您所看到的实际上是预期的行为。此外,这是您链接的视频中演示的内容。在视频中,客户端应用程序在每次 运行 时发送 2 条消息。一条消息发送到一个集群节点,第二条消息发送到另一个集群节点。这就是为什么每个节点上的 "Messages Added" 指标增加并且看起来同步的原因。当发送 2 条消息 (1+1=2) 时,每个节点上的 "Messages Added" 指标增加 1。添加到集群中队列的消息总数可以通过对集群中每个节点的 "Messages Added" 求和来确定。

了解此行为很重要,因为这意味着如果集群中的某个节点出现故障,则该节点上的所有消息都将变得不可用(如您所见)。如果您希望消息在节点故障的情况下可用,那么您需要配置一个 live/backup 对。有关如何完成此操作的更多详细信息,请参阅 EAP documentation