Friday 3 December 2021

Different Exchange Types in RabbitMQ

 Before this I have written two articles related to RabbitMQ here, one to demonstrate implementation of RabbitMQ in .NET : RabbitMQ in .NET Core

and second one to demonstrate the implementation of a Notification feature using RabbitMQ: Notification Queue : RabbitMQ in .NET Core

In my second example I have used “Direct” exchange type to build the Notification feature. In RabbitMQ Exchange and Queue are two very important concepts you need to understand to design your queuing server with RabbitMQ and that is what we are going to demonstrate here.

What is Queue

Queue is a storage to store ordered collection of messages and allows enqueue and dequeue in FIFO (first in first out) order. It has following properties to define the nature of Queue:
1. Name: it’s an unique name of the queue.
2. Durable: Decide if the queue will survive in case if broker restart.
3. Exclusive: Decide if the queue will be used by only one connection and then queue will be deleted with the connection closes.
4. Auto-delete: Decides if the queue will be auto deleted with its last consumer (if any) unsubscribes to the queue.
5. Arguments: This is optional and used by plugins and broker-specific features such as message TTL, queue length limit, etc)

What is Exchange

Exchange is a routing agent which routes the messages to different queues with the help of header attributes, bindings, and routing keys. In RabbitMQ, published messages are not directly sent to the queue instead message is published to exchange then it is sent to the queue.

In Above example, Exchange type is “fanout” which will publish the same message to all the available queues. Below is the code to set the Exchange as fanout for sender and publisher side both:

channel.ExchangeDeclare(exchange: "fanoutExchange", type: ExchangeType.Fanout);orchannel.ExchangeDeclare(exchange: "fanoutExchange", type: "fanout");

Lets see what are the different Exchange types are available and what’s the use of those.

Types of Exchange

There are four types of Exchange in RabbitMQ: Fanout, Direct, Headers and Topic.

  1. Fanout: This is the default exchange type and it just broadcasts all the messages it receives to all the queues it knows. Above example code shows how to define this exchange type and if exchange type is not defined then by default it will be fanout. In fanout exchange type headers, binding or routing keys will be ignored even if it is provided and messages will be published to all the available queues.

Fanout exchanges can be useful when the same message needs to be sent to one or more queues with consumers one at a time based on default Round Robin method. Hence there is a possibility that the message 11 will be received by Consumer 2 and message 22 will be received by consumer 2.

2. Direct: In this case, a message will go to the queues whose binding key exactly matches the routing key of the message. So that is the key, based on the routing key in message, exchange agent decides which queue it should go. This is very useful when we publisher published a message targeting only specific queue. Below is the code to define the specific routing key to drive the delivery queue.

Publisher code to publish the message with routing key.

channel.BasicPublish(exchange: "directExchange",
routingKey: "mysecretchannel",
basicProperties: properties,
body: body);

Subscriber code to read the message from queue with routing key

channel.ExchangeDeclare(exchange: "directExchange", type: ExchangeType.Direct);channel.QueueBind(queue: "myMsgQueue", exchange: "directExchange", routingKey: "mysecretchannel");

In Direct Exchange “One queue can be bind with multiple routing” hence this is useful when multiple type of messages needs to be delivered to one queue and this is possible when by binding one queue with multiple routing keys.

3. Topic: Topic exchange type also works on routing key match but instead of exact match, it matches the pattern of routing key. There are mandatory rule or guidelines needs to be followed to define the pattern of routing key and they are:
i. Routing key must be a list of words, delimited by dots.
ii. There can be as many words in the routing key as you like but only up to the limit of 255 bytes is possible.
iii. In the routing key you can use * (star) to substitute for exactly one word.
iv. In the routing key you can use # (hash) to substitute for zero or more words.

examples of valid rounting_key patters are:
lazy.orange.elephant*.*.elephantlazy.orange.#*.orange.*

Topic exchange is powerful in nature compare to other exchange types but at the same time it can also behave like other exchanges because of the pattern. Example:
i. When a queue is bound with “#” binding key — it will receive all the messages, regardless of the routing key — like in fanout exchange. i.e. rounting_key=”#”
ii. When special characters “*” and “#” aren’t used in bindings, the topic exchange will behave just like a direct one. i.e. routing_key=”abc”

Hence below all three diagram are a possible case for Topic exchange.

In the last diagram above here, all three messages with routing_key pattern as “lazy.orange”, “lazy.rabbit”, “lazy.#” can be delivered to Consumer 3 via queue 3 and it satisfy the pattern of lazy.{any word}

4. Headers: Headers exchange routes messages based on arguments containing headers and optional values. It is similar to the topic exchange, but messages routing is based on header values instead of routing keys. A message matches if the value of the header equals the value specified upon binding.

It is possible to bind a queue to a headers exchange using more than one header for matching. In this case, the broker needs one more piece of information from the application developer, namely, should it consider messages with any of the headers matching, or all of them? This is what the “x-match” binding argument is for. When the “x-match” argument is set to “any”, just one matching header value is sufficient. Alternatively, setting “x-match” to “all” mandates that all the values must match.

Note that headers beginning with the string x- will not be used to evaluate matches.

Like Topic there are rules for headers definition also. There are 2 types of headers matching allowed which are
i. any (similar to logical OR): a message sent to the Exchange should contain at least one of the headers that Queue is linked with, then the message will be routed to the Queue. i.e. { “x-match”, “any” ..}
ii. all (similar to logical AND): if a queue is bound with headers has x-match = all, messages that have all of its listed headers will be forwarded to the Queue. i.e. { “x-match”, “all” ..}

In above diagram, Queue 1 can receive both type of message as shown here but queue 2 can receive only the 2nd message which headers are exactly matching with queue headers.

Thank you reading. Don’t forget to clap if you like and leave comments for suggestion.

No comments:

Post a Comment