Clustered WildFly 10 domain messaging

2019-05-28 22:06发布

I have three machines located in different networks:

  • as-master
  • as-node-1
  • as-node-2

In as-master I have WildFly as domain host-master and the two nodes have WildFly as domain host-slave each starting an instance in the full-ha server group. From the as-master web console I can see the two nodes in the full-ha profile runtime and if I deploy a WAR it gets correctly started on both nodes.

Now, what I'm trying to achieve is messaging between the two instances of the WAR, i.e. sending a message from a producer instance in as-node-1, consumers in all the nodes should receive the message.

This is what I tried: added a topic to WildFly domain.xml:

<jms-topic name="MyTopic" entries="java:/jms/my-topic"/>

Create a JAX-RS endpoint to trigger a producer bound to the topic:

@Path("jms")
@RequestScoped
public class MessageEndpoint {

    @Inject
    JMSContext context;

    @Resource(mappedName = "java:/jms/my-topic")
    Topic myTopic;

    @GET
    public void sendMessage() {
         this.context.createProducer().send(this.myTopic, "Hello!");
    }

}

Create a MDB listening to the topic:

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(
        propertyName = "destination",
        propertyValue = "java:/jms/my-topic"
    ),
    @ActivationConfigProperty(
        propertyName = "destinationType",
        propertyValue = "javax.jms.Topic")
    )
)
public class MyMessageListener implements MessageListener {

    private final static Logger LOGGER = /* ... */

    public void onMessage(Message message) {
        try {
            String body = message.getBody(String.class)
            LOGGER.info("Received message: " + body);
        } catch (JMSException e) {
            throw new RuntimeException(e);
        }
    }

}

But when I curl as-node-1/jms I see the log only in as-node-1, and when I curl as-node-2/jms I see the log only in as-node-2.

Shouldn't the message be delivered on all the nodes where the WAR is deployed? What am I missing?

1条回答
Summer. ? 凉城
2楼-- · 2019-05-28 22:20

As I've come with the exactly same question - put the answer here.

Yes, messages should be delivered to all nodes if a destination is a Topic.

With the default configuration ActiveMQ Artemis uses broadcast to discover and connect to other ActiveMQ instances on other nodes (within the same discovery-group):

<discovery-group name="dg-group1" jgroups-channel="activemq-cluster"/>
<cluster-connection name="my-cluster" discovery-group="dg-group1" connector-name="http-connector" address="jms"/>

Still need to ensure that a JNDI name for a jms-topic starts with the "jms" to match the address="jms" in the line above (what is OK in your case: "java:/jms/my-topic")

The only thing missed in your example to get it working on all nodes is :
<cluster password="yourPassword" user="activemqUser"/>
(for sure activemqUser user must be added earlier, e.g. with the addUser.sh script).

This let ActiveMQ instances to communicate each other. So called Core Bridge connection is created between nodes. As stated in ActiveMQ manual :

..this is done transparently behind the scenes - you don't have to declare an explicit bridge for each node

If everything is OK then the bridge may be found in server.log: AMQ221027: Bridge ClusterConnectionBridge@63549ead [name=sf.my-cluster ...] is connected.

Btw, if a destination is a Queue then ActiveMQ will not send a message to other nodes unless a message is not consumed locally.

P.s. as answered here this refers to a classic approach to distribute an event to all nodes in a cluster.

查看更多
登录 后发表回答