代码之家  ›  专栏  ›  技术社区  ›  MI-Merc

远程代理故障切换后,Wildfly JMS消息发送失败

  •  0
  • MI-Merc  · 技术社区  · 3 年前

    我有一个Wildfly消息实时/备份对和一个Wildfly实例作为应用服务器(所有版本均为26.0.1)。我将Wildfly与集成的ActiveMQ服务器一起用作远程消息代理(而不是直接使用普通的ActiveMQ服务器)。

    用于测试我使用的

    • helloworld mdb快速入门示例( https://github.com/wildfly/quickstart/tree/main/helloworld-mdb )部署在Wildfly应用服务器上,MDB接收消息,servlet使用注入的JmsContext和注入的队列/主题发送消息(我重命名了队列/主题,删除了@JMSDestinitionDefinitions,以便在消息传递activemq子系统配置中定义目的地)
    • 还有两个简单的JMS客户机程序:一个用于向队列发送消息,另一个用于从队列接收消息(它们只需按照默认路径:获取InitialContext,查找目标和连接工厂,并创建连接和会话)

    我的设置几乎正常。在消息代理故障切换/回切时,客户端程序和MDB会自动重新连接。但是,quickstart示例中的servlet在实时/备份对故障切换后发送消息时会阻塞,并且不会发送任何消息。它在大约一分钟后失败,堆栈跟踪如下:

    12:15:53,496 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /helloworld-mdb/HelloWorldMDBServletClient: javax.jms.JMSRuntimeException: AMQ219014: Timed out after waiting 30,000 ms for response when sending packet 71
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.JmsExceptionUtils.convertToRuntimeException(JmsExceptionUtils.java:88)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQJMSProducer.send(ActiveMQJMSProducer.java:100)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQJMSProducer.send(ActiveMQJMSProducer.java:124)
            at deployment.helloworld-mdb.war//org.jboss.as.quickstarts.servlet.HelloWorldMDBServletClient.doGet(HelloWorldMDBServletClient.java:95)
            at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:503)
            at javax.servlet.api@2.0.0.Final//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
            at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
            at org.wildfly.security.elytron-web.undertow-server@1.10.1.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
            at org.wildfly.security.elytron-base@1.18.3.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
            at org.wildfly.security.elytron-base@1.18.3.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
            at org.wildfly.security.elytron-base@1.18.3.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
            at org.wildfly.security.elytron-web.undertow-server@1.10.1.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
            at io.undertow.core@2.2.14.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
            at io.undertow.core@2.2.14.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
            at io.undertow.core@2.2.14.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
            at org.wildfly.security.elytron-web.undertow-server-servlet@1.10.1.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
            at io.undertow.core@2.2.14.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
            at io.undertow.core@2.2.14.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
            at io.undertow.core@2.2.14.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:275)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:79)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:134)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:131)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
            at org.wildfly.extension.undertow@26.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1544)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:255)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:79)
            at io.undertow.servlet@2.2.14.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:100)
            at io.undertow.core@2.2.14.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
            at io.undertow.core@2.2.14.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:852)
            at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
            at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
            at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
            at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
            at org.jboss.xnio@3.8.5.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1280)
            at java.base/java.lang.Thread.run(Thread.java:833)
    Caused by: javax.jms.JMSException: AMQ219014: Timed out after waiting 30,000 ms for response when sending packet 71
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:539)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.protocol.core.impl.ChannelImpl.sendBlocking(ChannelImpl.java:443)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.protocol.core.impl.ActiveMQSessionContext.sendFullMessage(ActiveMQSessionContext.java:552)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.client.impl.ClientProducerImpl.sendRegularMessage(ClientProducerImpl.java:296)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.client.impl.ClientProducerImpl.doSend(ClientProducerImpl.java:268)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.client.impl.ClientProducerImpl.send(ClientProducerImpl.java:143)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.client.impl.ClientProducerImpl.send(ClientProducerImpl.java:125)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQMessageProducer.doSendx(ActiveMQMessageProducer.java:483)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQMessageProducer.send(ActiveMQMessageProducer.java:220)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQMessageProducer.send(ActiveMQMessageProducer.java:207)
            at org.apache.activemq.artemis.ra@2.19.0//org.apache.activemq.artemis.ra.ActiveMQRAMessageProducer.send(ActiveMQRAMessageProducer.java:137)
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.jms.client.ActiveMQJMSProducer.send(ActiveMQJMSProducer.java:97)
            ... 53 more
    Caused by: ActiveMQConnectionTimedOutException[errorType=CONNECTION_TIMEDOUT message=AMQ219014: Timed out after waiting 30,000 ms for response when sending packet 71]
            ... 65 more
    

    我跟着 7.8.12. Connect a pooled-connection-factory to a Remote Artemis Server ,但我使用http连接器而不是远程连接器,因为使用Wildfly作为远程代理。

    所有配置都基于 独立全哈。xml 只需进行以下修改。

    消息传递live Wildfly服务器“消息传递节点-1”:

    • 更改群集密码
    • 添加了复制主机
    • 更改了群集连接名称
    • 增加了两个目的地
    ...
    <subsystem xmlns="urn:jboss:domain:messaging-activemq:13.0">
        <server name="default">
            <security elytron-domain="ApplicationDomain"/>
            <cluster password="${jboss.messaging.cluster.password:**changed-password**}"/>
            <statistics enabled="${wildfly.messaging-activemq.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
            <replication-master cluster-name="messaging-cluster" group-name="activemq-group"/><!-- added -->
            <security-setting name="#">
                <role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
            </security-setting>
            <address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10" redistribution-delay="1000"/>
            <http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
            <http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
                <param name="batch-delay" value="50"/>
            </http-connector>
            <in-vm-connector name="in-vm" server-id="0">
                <param name="buffer-pooling" value="false"/>
            </in-vm-connector>
            <http-acceptor name="http-acceptor" http-listener="default"/>
            <http-acceptor name="http-acceptor-throughput" http-listener="default">
                <param name="batch-delay" value="50"/>
                <param name="direct-deliver" value="false"/>
            </http-acceptor>
            <in-vm-acceptor name="in-vm" server-id="0">
                <param name="buffer-pooling" value="false"/>
            </in-vm-acceptor>
            <jgroups-broadcast-group name="bg-group1" jgroups-cluster="activemq-cluster" connectors="http-connector"/>
            <jgroups-discovery-group name="dg-group1" jgroups-cluster="activemq-cluster"/>
            <cluster-connection name="messaging-cluster" address="jms" connector-name="http-connector" discovery-group="dg-group1"/>
            <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
            <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
            <jms-queue name="TestQueue" entries="java:jboss/exported/queue/TestQueue" durable="true"/>
            <jms-topic name="TestTopic" entries="java:jboss/exported/topic/TestTopic"/>
            <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
            <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector" ha="true" block-on-acknowledge="true" reconnect-attempts="-1"/>
            <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
        </server>
    </subsystem>
    ...
    

    消息备份Wildfly服务器“Messaging-node-2”
    与上述相同,只是复制主机被复制从机替换

    ...
    <subsystem xmlns="urn:jboss:domain:messaging-activemq:13.0">
        <server name="default">
            ...
            <replication-slave cluster-name="messaging-cluster" group-name="activemq-group"/>
            ...
        </server>
    </subsystem>
    ...
    

    应用程序Wildfly服务器“应用程序节点1”
    用远程代理替换了集成的ActiveMQ服务器定义,并添加了外部目标。注意,EJB的工厂名称和子系统的默认连接使用JNEE条目:

    ...
    <subsystem xmlns="urn:jboss:domain:messaging-activemq:13.0">
        <http-connector name="node-1-http-connector" socket-binding="messaging-node-1" endpoint="http-acceptor"/>
        <http-connector name="node-2-http-connector" socket-binding="messaging-node-2" endpoint="http-acceptor"/>
        <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="node-1-http-connector node-2-http-connector" user="JmsTest" password="JmsTest"/>
        <external-jms-queue name="TestQueue" entries="java:/queue/TestQueue"/>
        <external-jms-topic name="TestTopic" entries="java:/topic/TestTopic"/>
    </subsystem>
    ...
    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        ...
        <outbound-socket-binding name="messaging-node-1">
            <remote-destination host="..." port="8180"/>
        </outbound-socket-binding>
        <outbound-socket-binding name="messaging-node-2">
            <remote-destination host="..." port="8180"/>
        </outbound-socket-binding>
    </socket-binding-group>
    ...
    

    servlet:

    @WebServlet("/HelloWorldMDBServletClient")
    public class HelloWorldMDBServletClient extends HttpServlet {
    
        private static final long serialVersionUID = -8314035702649252239L;
    
        private static final int MSG_COUNT = 5;
    
        @Inject
        private JMSContext context;
    
        @Resource(lookup = "java:/queue/TestQueue")
        private Queue queue;
    
        @Resource(lookup = "java:/topic/TestTopic")
        private Topic topic;
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html");
            PrintWriter out = resp.getWriter();
            out.write("<h1>Quickstart: Example demonstrates the use of <strong>JMS 2.0</strong> and <strong>EJB 3.2 Message-Driven Bean</strong> in JBoss EAP.</h1>");
            try {
                boolean useTopic = req.getParameterMap().keySet().contains("topic");
                final Destination destination = useTopic ? topic : queue;
    
                out.write("<p>Sending messages to <em>" + destination + "</em></p>");
                out.write("<h2>The following messages will be sent to the destination:</h2>");
                for (int i = 0; i < MSG_COUNT; i++) {
                    String text = "This is message " + (i + 1);
                    **context.createProducer().send(destination, text); // fails**
                    out.write("Message (" + i + "): " + text + "</br>");
                }
                out.write("<p><i>Go to your JBoss EAP server console or server log to see the result of messages processing.</i></p>");
            } finally {
                if (out != null) {
                    out.close();
                }
            }
        }
    
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

    过程:启动实时/备份对和应用服务器,部署helloworld mdb。war连接到应用服务器,并在web浏览器中加载servlet页面。要进行故障切换,请关闭实时消息服务器。在web浏览器中重新加载servlet页面。结果:web浏览器持续等待大约一分钟,然后收到servlet到目前为止打印的内容(“……以下消息将被发送到目标:“<EOF>”)。

    使用JMS客户端程序发送和接收消息在故障转移后工作。MDB在故障转移后会不断接收消息。只是应用服务器消息发送失败。

    我没有成功

    • 已尝试更改群集连接的超时配置值
    • 已将消息发送到无状态会话bean(以测试事务)
    • 将JmsContext替换为连接工厂,但无效;createSession()阻塞,然后以“…原因:ActiveMQConnectionTimedOutException[errorType=CONNECTION_TIMEDOUT message=AMQ219014:在发送数据包63时等待30000毫秒响应后超时]”失败
    ...
    @Resource(mappedName = "java:/JmsXA")
    private ConnectionFactory connectionFactory;
    
    @Resource(mappedName = "java:/queue/TestQueue")
    private Queue queue;
    ...
    Connection connection = connectionFactory.createConnection();
    Session session = connection.createSession();
    

    问题:

    • 消息和应用服务器配置是否适合我的设置?
    • 故障转移后,使用注入的JmsContext和队列发送消息失败的原因可能是什么?

    我将非常感谢您的帮助。


    更新1

    仅供参考:当即时消息服务器关闭时,应用服务器会注意到:

    17:11:40,908 WARN  [org.apache.activemq.artemis.core.client] (Thread-2 (ActiveMQ-client-global-threads)) AMQ212037: Connection failure to 172.*.*.*/172.*.*.*:8180 has been detected: AMQ219015: The connection was disconnected because of server shutdown [code=DISCONNECTED]
    

    ...重复了大约30次,但有一个例外:

    17:11:40,904 WARN  [org.jboss.activemq.artemis.wildfly.integration.recovery] (Thread-2 (ActiveMQ-client-global-threads)) being disconnected for server shutdown: ActiveMQDisconnectedException[errorType=DISCONNECTED message=AMQ219015: The connection was disconnected because of server shutdown]
            at org.apache.activemq.artemis@2.19.0//org.apache.activemq.artemis.core.client.impl.ClientSessionFactoryImpl$CloseRunnable.run(ClientSessionFactoryImpl.java:1089)
            at org.apache.activemq.artemis.journal//org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:42)
            at org.apache.activemq.artemis.journal//org.apache.activemq.artemis.utils.actors.OrderedExecutor.doTask(OrderedExecutor.java:31)
            at org.apache.activemq.artemis.journal//org.apache.activemq.artemis.utils.actors.ProcessorBase.executePendingTasks(ProcessorBase.java:65)
            at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
            at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
            at org.apache.activemq.artemis.journal//org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118)
    
    0 回复  |  直到 3 年前