{"id":36,"date":"2018-05-29T22:46:19","date_gmt":"2018-05-30T02:46:19","guid":{"rendered":"http:\/\/bhoey.com\/blog\/?p=36"},"modified":"2020-06-24T11:53:08","modified_gmt":"2020-06-24T15:53:08","slug":"guaranteed-topic-delivery-using-apachemq-virtual-destinations","status":"publish","type":"post","link":"https:\/\/bhoey.com\/blog\/guaranteed-topic-delivery-using-apachemq-virtual-destinations\/","title":{"rendered":"Guaranteed Topic Delivery using ActiveMQ Virtual Destinations"},"content":{"rendered":"<h3>Background<\/h3>\n<p>The original JMS spec first arrived in 2001 with JSR 914. At the time several enterprise messaging systems were already widely available however each had their own unique features and mechanisms which required software that wanted to talk on a given messaging bus to be tightly-coupled to the specific messaging system implementation in use.<\/p>\n<p>Given that \"tightly-coupled\" is something you want to avoid in your enterprise systems, there was a push to abstract away these implementation-specific system aspects from the messaging client code. To address this, the JMS was developed to define a standardized, consistent programming interface that would work across different JMS-provider implementations. The JMS spec, by its abstracted nature, could only define the lowest-common-denominator of messaging constructs so that they could apply to (or be adapted for) the widest number of messaging systems. The JMS therefore defined two core messaging delivery mechanisms (also referred to as destinations): <b>queues<\/b> and <b>topics<\/b>.<\/p>\n<ul>\n<li><b>Queues<\/b> are used for point-to-point messaging (1-to-1), where a message sent to a given queue will only be delivered to a single consumer<\/li>\n<\/ul>\n<p style=\"padding-left: 80px;\"><img loading=\"lazy\" class=\"alignnone  wp-image-289\" src=\"http:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-queue.png\" alt=\"image of queue\" width=\"365\" height=\"28\" srcset=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-queue.png 497w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-queue-300x23.png 300w\" sizes=\"(max-width: 365px) 100vw, 365px\" \/><\/p>\n<ul>\n<li><b>Topics<\/b> on the other hand are used for pub\/sub messaging (1-to-many), where a message sent to a topic will be delivered to all subscribers currently listening to that topic.<\/li>\n<\/ul>\n<p style=\"padding-left: 80px;\"><img loading=\"lazy\" class=\"alignnone  wp-image-290\" src=\"http:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-pubsub.png\" alt=\"image of message topic\" width=\"370\" height=\"127\" srcset=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-pubsub.png 446w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-pubsub-300x103.png 300w\" sizes=\"(max-width: 370px) 100vw, 370px\" \/><\/p>\n<p>Beyond the producer\/consumer topology differences between the two, there is another key aspect to consider: <b>time dependency<\/b>.<\/p>\n<h3>Time Dependency<\/h3>\n<p>A message sent to a queue will remain on that queue until a consumer removes it. In other words, a queue consumer can be brought online and all messages that were sent to the queue prior to the consumer coming online will then be delivered to it.<\/p>\n<p>However, as hinted above, by default subscribers need to have an active subscription at the time a message is published in order to receive it. Any messages published when the subscriber is not listening will not be delivered to said subscriber. There is a slight exception to this rule, <b>durable subscriptions<\/b>, which allow subscribers to receive all messages between the time they subscribe until they unsubscribe, even if the subscriber was offline when a message was sent.<\/p>\n<p>There are practical limitations to durable subscriptions which reduces the number of use-cases where they would be sufficient. One of the biggest constraints is that durable subscriptions don't cover messages that were sent prior to the subscriber creating the durable subscription. For example if the sending system starts broadcasting messages at 7:00am and the receiving system registers a durable listener at 7:30am, all messages produced between 7:00a-7:30a will not be delivered to the subscriber. Although there are some situations where this type of operation is sufficient, the more common requirement is that the receiving system get ALL messages from the sending system, whether the receiving system was alive or not. What is needed is a pub\/sub model but with the delivery guarantees that queues provide. This is where <b>ActiveMQ Virtual Destinations<\/b> can help.<\/p>\n<h3>Virtual Destinations<\/h3>\n<p>ActiveMQ Virtual Destinations are a way of mapping logical destinations to one or more actual (also called physical) destinations. There are a couple types of virtual destinations available but the one we will focus on is referred to as a <b>Composite Topic<\/b>. This particular virtual destination will behave as a topic destination for publishers, but we can map that topic to a series of queues (and\/or other topics) in order to achieve the particular delivery characteristics that we are shooting for.<\/p>\n<p style=\"margin-left: 60px; margin-right: 60px; padding-left: 10px; padding-right: 10px; text-align: justify; border: 2px solid black; background-color: #f7f8fa;\">Side note: I did not use the phrase \"virtual topic\" above (which would have seem to have been a better word choice) because \"virtual topic\" denotes a specific kind of ActiveMQ virtual destination! Virtual topics are similar to composite topics except that virtual topics are simplified virtual destinations that can be dynamically created by messaging clients based on a naming convention (ie ActiveMQ topic \"VirtualTopic.FOO\" will create a dynamic, virtual topic).<\/p>\n<h3>Composite Topics<\/h3>\n<p>Composite Topics are set up in the ActiveMQ broker configuration and allow for flexibility in designing messaging architecture.<\/p>\n<p>Both these aspects are key:<\/p>\n<ul>\n<li>We want the flexibility to map a single topic to multiple queues, and<\/li>\n<li>We want to define this setup in the broker's initialization file so that the broker knows to create the physical queues on startup so it can begin dropping messages sent to the topic to them.<\/li>\n<\/ul>\n<p style=\"padding-left: 80px;\"><img loading=\"lazy\" class=\"alignnone  wp-image-291\" src=\"http:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-comptopic.png\" alt=\"image of composite topic\" width=\"414\" height=\"197\" srcset=\"https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-comptopic.png 544w, https:\/\/bhoey.com\/blog\/wp-content\/uploads\/2019\/06\/MQ-comptopic-300x143.png 300w\" sizes=\"(max-width: 414px) 100vw, 414px\" \/><\/p>\n<p>This is what it looks like inside the conf\/activemq.xml:<\/p>\n<div>\n<div id=\"highlighter_976313\" class=\"syntaxhighlighter nogutter  xml\">\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n<tbody>\n<tr>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">broker<\/code> <code class=\"xml plain\">...&gt;<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"xml plain\">...<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml comments\">&lt;!-- Optional: Pre-define topic\/queues --&gt;<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">destinations<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">topic<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"myLogicalTopic\"<\/code> <code class=\"xml plain\">\/&gt;<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">queue<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"queueA\"<\/code> <code class=\"xml plain\">\/&gt;<\/code><\/div>\n<div class=\"line number7 index6 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">queue<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"queueB\"<\/code> <code class=\"xml plain\">\/&gt;<\/code><\/div>\n<div class=\"line number8 index7 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">destinations<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number9 index8 alt2\"><\/div>\n<div class=\"line number10 index9 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">destinationInterceptors<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number11 index10 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">virtualDestinationInterceptor<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number12 index11 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">virtualDestinations<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number13 index12 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">compositeTopic<\/code> <code class=\"xml color1\">name<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"myLogicalTopic\"<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number14 index13 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">forwardTo<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number15 index14 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">queue<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"queueA\"<\/code><code class=\"xml plain\">\/&gt;<\/code><\/div>\n<div class=\"line number16 index15 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">queue<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"queueB\"<\/code><code class=\"xml plain\">\/&gt;<\/code><\/div>\n<div class=\"line number17 index16 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;<\/code><code class=\"xml keyword\">queue<\/code> <code class=\"xml color1\">physicalName<\/code><code class=\"xml plain\">=<\/code><code class=\"xml string\">\"queueC\"<\/code><code class=\"xml plain\">\/&gt; <\/code><code class=\"xml comments\">&lt;!-- This queue was not defined above to <\/code><\/div>\n<div class=\"line number18 index17 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml comments\">demonstrate that ActiveMQ will create <\/code><\/div>\n<div class=\"line number19 index18 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml comments\">a target destination on the first message --&gt;<\/code><\/div>\n<div class=\"line number20 index19 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">forwardTo<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number21 index20 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">compositeTopic<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number22 index21 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">virtualDestinations<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number23 index22 alt2\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">virtualDestinationInterceptor<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number24 index23 alt1\"><code class=\"xml spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">destinationInterceptors<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<div class=\"line number25 index24 alt2\"><code class=\"xml plain\">&lt;\/<\/code><code class=\"xml keyword\">broker<\/code><code class=\"xml plain\">&gt;<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>Producer\/Consumer Setup<\/h3>\n<p>With the broker squared away, the only thing left is to add the appropriate code to the producer(s) and consumer(s) programs. Fortunately since the broker is doing the heavy lifting of forwarding messages behind the scenes, we can just set up producer(s) to publish to the topic and each consumer to connect to their assigned queue as you normally would. From the messaging client perspective there is nothing special or exotic that needs to be additionally configured.<\/p>\n<h3>Trade-offs<\/h3>\n<p>Astute readers may have already guessed that there is some trade-offs involved going this route. The most obvious one is that in the way we've configured it, each receiving system would require its own queue, effectively losing the ability for subscribers to dynamically register. In practice this isn't usually much of an issue since a) normally the number of receiving systems is known and limited and b) we could have easily added a physical topic to the mapping so that messages would also be forwarded to a standard topic. In addition, placing messages in queues rather than say durable subscriptions makes the operation much more visible and easy to work with and even promotes receiving systems' ability to implement load-balancing.<\/p>\n<h3>Conclusion<\/h3>\n<p>Using virtual destinations the producer can enjoy the simplicity of a pub\/sub model with the assurance that messages will be waiting for consumers to pull them from the broker when they are up and ready. Though any robust messaging architecture will require more design, planning, and configuration than we've touched on here, virtual destinations are an approach that may greatly simplify some otherwise very difficult use-cases.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The original JMS spec first arrived in 2001 with JSR 914. At the time several enterprise messaging systems were already widely available however each had their own unique features and mechanisms which required software that wanted to talk on a given messaging bus to be tightly-coupled to the specific messaging system implementation in use.<\/p>\n<p>Given that \"tightly-coupled\" is something you want to avoid in your enterprise systems, there was a push to abstract away these implementation-specific system aspects from the messaging client code. To address this, the JMS was developed to define a standardized, consistent programming interface that would work across different JMS-provider implementations.&nbsp;<a href=\"https:\/\/bhoey.com\/blog\/guaranteed-topic-delivery-using-apachemq-virtual-destinations\/\">[Continue&nbsp;reading...] <span class=\"screen-reader-text\">Guaranteed Topic Delivery using ActiveMQ Virtual Destinations<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":811,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[58],"tags":[19,22,18,20,21],"_links":{"self":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/36"}],"collection":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/comments?post=36"}],"version-history":[{"count":35,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/36\/revisions"}],"predecessor-version":[{"id":813,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/posts\/36\/revisions\/813"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/media\/811"}],"wp:attachment":[{"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/media?parent=36"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/categories?post=36"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bhoey.com\/blog\/wp-json\/wp\/v2\/tags?post=36"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}