Azure Service Bus Queue and Topic are two popular messaging patterns used in cloud-based applications. A Service Bus Queue is a first-in-first-out (FIFO) messaging pattern where messages are processed in the order they are received.
Service Bus Queues are designed for scenarios where messages need to be processed in a specific order, such as in a workflow where each step depends on the previous one. They're also great for handling high volumes of messages.
A Service Bus Topic, on the other hand, is a publish-subscribe messaging pattern where messages are routed to specific subscribers based on their subscription filters. This allows for more flexibility and scalability in handling messages.
Service Bus Topics are ideal for scenarios where multiple subscribers need to process messages independently, such as in a real-time analytics system where different teams need to process data in different ways.
What is Azure Service Bus Queue vs Topic?
Azure Service Bus Queue and Topic are two messaging patterns that help you communicate between different components of your application.
A Service Bus Queue is a First-In-First-Out (FIFO) messaging pattern, where messages are received in the order they were sent.
It's perfect for scenarios where order matters, like processing transactions or handling critical business logic.
In contrast, a Service Bus Topic is a publish-subscribe messaging pattern, where messages are published to a topic and subscribers can receive messages based on specific criteria.
This allows for more flexibility and scalability in your application, making it ideal for scenarios with high volumes of messages or changing message requirements.
What Are Queues?
Queues are a fundamental concept in messaging patterns, allowing producers to send messages to a central location, known as a queue, for later processing by consumers.
A queue is a First-In-First-Out (FIFO) data structure, meaning the order in which messages are sent is the same order in which they are received by the consumer.
Messages in a queue are typically processed by a single consumer, which retrieves messages from the head of the queue and processes them one by one.
In a queue, messages are stored in memory and on disk, ensuring that messages are not lost in case of a service failure.
Queues are designed to handle scenarios where messages are sent by one system and processed by another, often in a different location or at a different time.
Azure
Azure Service Bus is a powerful tool for messaging and communication, and it comes with two main components: Queues and Topics.
Queues follow a simple messaging protocol, where messages are delivered to a Queue that resides in a Service Bus Namespace, and then received by a receiver in initial or later stage.
In Queues, messages are processed via FIFO (First-In-First-Out) pattern, which means the first message delivered into the Queue will be the first one to be retrieved by the receiver.
One of the biggest advantages of Azure Service Bus Queues is that a message stays in a queue as long as the receiver picks it up.
Topics are similar to Queues but can have multiple, independent subscriptions. A subscriber to a Topic can receive a copy of each message sent to that Topic.
Multiple receivers could be allocated to a subscription, and a Topic can have zero or more subscriptions, but a subscription can only belong to one Topic.
If you don't want all subscribers to read all the messages, you can apply rules to specify additional actions to filter or to modify message properties.
With Azure Service Bus Management, you can process active/dead-letter messages to other Queues or Topics, and backup messages to storage blob.
You can also remote actions like Enable/Disable the Service Bus Queues or view the properties, making it easy to manage your Topics and Topic Subscriptions.
Creating and Configuring
Creating a Service Bus Namespace is a container for all messaging components, where you can have both queues and topics depending on the SKU used. You can think of it as a server with its own capacity of a large cluster of all-active VMs.
To create a Service Bus namespace, you declare a resource of type Microsoft.ServiceBus/namespaces and give it a name, location, and SKU, using the Basic SKU for this example. A Service Bus Namespace is an available and reliable service at scale, without needing to manage the service.
You can create a queue by declaring a resource block of type Microsoft.ServiceBus/namespaces/queues, giving it a name, and using your Service Bus namespace as the parent. This lets Bicep know that the queue belongs in the namespace.
Creating a Namespace in Bicep
A Service Bus Namespace is a container for all messaging components, and we can provision one by declaring a resource of type Microsoft.ServiceBus/namespaces.
To create a namespace, we need to give it a name, location, and SKU. We can use the Basic SKU for a queue, but for a topic, we need to use either the Standard or Premium pricing tier.
We can create a namespace using the type Microsoft.ServiceBus/namespaces, and give it a name and location. We can also specify the SKU, such as the Basic SKU.
A namespace can have both queues and topics, depending on the SKU we use. For example, we can create a queue within a namespace, but topics aren't supported at the Basic pricing tier.
To create a namespace, we need to use the correct resource type, such as Microsoft.ServiceBus/namespaces, and specify the parent resource, such as the Service Bus namespace.
We can create a namespace with a queue or a topic by declaring a resource block of the correct type, such as Microsoft.ServiceBus/namespaces/queues or Microsoft.ServiceBus/namespaces/topics.
Partition Enablement
Partition Enablement is a powerful feature in Azure Service Bus Queues that allows messages to be stored in multiple fragments, or partitions, and handled by a dedicated message broker for each partition.
This means that as your queue grows, you can scale your message handling to keep up with demand without having to worry about performance issues.
In partitioned queues, messages will be stored in multiple fragments, and the requests are handled by the dedicated message broker of that partition.
The Enable Partition property is only available in Azure Service Bus Queues, not in Topic Subscriptions.
This allows you to take advantage of partitioning in queues, but not in topics, which may require a different approach to scaling your message handling.
Sending and Retrieving Messages
To send messages to an Azure Service Bus queue, you can use the Azure.Messaging.ServiceBus NuGet package and create a ServiceBusClient object with the connection string of your Service Bus.
You can then create a ServiceBusSender object for your queue and add messages to a ServiceBusMessageBatch object using the TryAddMessage() method. Once you've added all your messages, you can send them to your queue using the SendMessagesAsync() method.
To clean up your resources, you should call DisposeAsync() on both your ServiceBusSender and ServiceBusClient objects.
The process of sending messages to a Service Bus queue is similar to sending messages to a Service Bus topic, but you don't need to pass in the name of a topic.
To retrieve messages from a queue, you can create a ServiceBusProcessor object and add event handlers to process the messages. The event handlers should handle the processing of the message and any exceptions that may be thrown.
Here's a step-by-step guide to retrieving messages from a queue:
1. Create a ServiceBusClient object with the connection string of your Service Bus.
2. Create a ServiceBusProcessor object for your queue.
3. Add event handlers to process the messages and handle any exceptions.
4. Start processing messages from your Service Bus queue using the StartProcessingAsync() method.
5. Once all your messages are processed, stop the processing of messages from the queue using the StopProcessingAsync() method.
6. Clean up your objects by calling DisposeAsync() on both your ServiceBusProcessor and ServiceBusClient objects.
Note that while synchronous invocation of the Send and Receive methods is shown for simplicity, it's recommended to use the corresponding asynchronous methods to free the calling thread from blocking while waiting to receive a message.
Topics and Subscriptions
Topics in Azure Service Bus are different from queues because they allow multiple subscribers to receive their own copy of a message from the topic. This works in a pub/sub pattern, where messages are published to the topic and multiple clients subscribe to it.
A topic is like a virtual queue that receives copies of messages sent to it, and consumers receive messages from a subscription identically to the way they receive messages from a queue. Subscriptions can use filters to restrict the messages they want to receive.
Publishers send messages to a topic in the same way they send messages to a queue, but consumers don't receive messages directly from the topic. Instead, they receive messages from subscriptions of the topic, which resemble virtual queues that receive copies of the messages sent to the topic.
What Are Topics?
Topics are different from queues because they allow multiple subscribers to receive a copy of the message from the topic. This works in a pub/sub pattern where messages are published to the topic and multiple clients subscribe to receive them.
In a topic, consumers don't directly consume the message from the topic. Instead, they create subscriptions that subscribe to the topic and receive a copy of the message.
Publishers send messages to a topic in the same way they send messages to a queue. But, consumers receive messages from subscriptions of the topic, not directly from the topic itself.
Sending and Subscribing in C
To send messages to a topic, you create a producer program that passes the topic name to a ServiceBusSender object, which is almost identical to the producer program for a queue.
You can subscribe to a topic by asking the MessagingFactory for an instance of the SubscriptionClient, passing in the topic name, subscription name, and ReceiveMode.
To receive messages from a subscription, you call Receive on the SubscriptionClient instance, which will deliver messages that match the subscription's rules.
You can add rules to a subscription by calling the AddRule method on the SubscriptionClient, which allows you to filter messages based on specific criteria.
Here's a comparison of the producer and consumer programs for a queue and a topic:
Note that the consumer program for a topic is similar to the consumer program for a queue, but with additional parameters for the topic and subscription names.
Topics and Subscriptions
Topics and Subscriptions are a powerful tool for scaling to large numbers of recipients.
A topic allows for one-to-many communication in a publish and subscribe pattern, which is useful for scaling to large numbers of recipients.
Each published message is made available to each subscription registered with the topic.
Publishers send a message to a topic in the same way that they send messages to a queue.
Subscriptions can use filters to restrict the messages that they want to receive.
Subscribers receive messages from a subscription identically to the way they receive messages from a queue.
A subscription resembles a virtual queue that receives copies of the messages that are sent to the topic.
Consumers receive messages from a subscription by creating a SubscriptionClient instance and passing it the name of the topic, the subscription, and the ReceiveMode.
To read all of the messages currently available in the subscription, you can call Receive on the SubscriptionClient instance.
Each matching rule on a subscription will result in a message being delivered to the subscriber.
Subscriptions support the same patterns as queues, including competing consumer, temporal decoupling, load leveling, and load balancing.
Auto-Forwarding
Auto-Forwarding is a powerful feature that allows you to automatically send messages to a specified destination.
You can auto-forward messages from a Topic to a Queue or another Topic, which is super convenient for managing your messages.
Messages can also be auto-forwarded from a Topic Subscription to a Queue or Topic, giving you even more flexibility.
Auto-forwarding from a Topic Subscription to a Queue or Topic is a great way to ensure that all your messages are being routed correctly.
The destination of an auto-forwarded message cannot be a Topic Subscription, so make sure you choose a Queue or Topic as the final destination.
Message Handling and Receive Modes
Message handling is a crucial aspect of Azure Service Bus queues and topics. Service Bus allows you to specify two different modes for consumers to receive messages, Receive and delete, and Peek lock.
In Receive and delete mode, messages are marked as consumed and returned to the consumer application after a request is received from the consumer. This mode is best for scenarios where the application can tolerate missing messages if a failure occurs.
The Peek lock mode, on the other hand, provides at-least-once delivery semantics, allowing more than one consumer to potentially read the message. This mode is preferred because it supports competing consumer patterns and allows for more resilience in case something goes wrong during message processing.
Here are the key differences between Receive and delete and Peek lock modes:
In Peek lock mode, messages are consumed in two phases: first, the message is read, and then, after processing, the Complete method is called to inform the fabric that it's okay to delete the message. If the consumer is unable to process the message, the Abandon method can be called to unlock the message and make it available for other consumers to read.
Receive Modes
In message handling, there are two primary receive modes to consider: Receive and delete, and Peek lock.
Receive and delete is the simplest mode, where the message is marked as consumed and returned to the consumer application after a request is made. This mode works best for scenarios where the application can tolerate missing a message if a failure occurs.
Peek lock mode, on the other hand, provides "At Least Once" delivery semantics, allowing more than one consumer to potentially read the message. This mode is preferred because it supports the competing consumer pattern and allows for more resilience in the event that something goes wrong in processing the message.
In Peek lock mode, the receive operation becomes two-stage, making it possible to support applications that can't tolerate missing messages. After a successful call to Receive on the QueueClient, you must call the Complete method on the QueueClient, along with the LockToken that was assigned to the message, to complete the read and inform the fabric that it's OK to delete the message.
If the consumer is unable to process the message, it can call the Abandon method on the QueueClient instance to inform the fabric that the message should be unlocked and made available for other consumers to read.
Here are the key differences between Receive and delete and Peek lock modes:
In Peek lock mode, if the Complete method is not called within 30 seconds (the default lock duration), the message is unlocked and made available for the next consumer.
Brokered Class
The Brokered Class is a key concept in message handling, and it's essential to understand its capabilities. It represents a unit of communication between Service Bus parties.
The BrokeredMessage class contains a message body and supports the use of properties outside of the body for storing metadata, headers, or payloads themselves. This allows for flexible and efficient message handling.
To create a BrokeredMessage, you simply instantiate it with its default constructor, or by passing in a serializable type. For example, you can pass in an instance of a custom class, like an "Order" class, and a BrokeredMessage will be created.
The payload of a BrokeredMessage must be serializable, and it can be up to 256 KB in size. Each BrokeredMessage instance also has a TimeToLive (TTL) property associated with the instance, which can be set to a time span according to your requirements.
The BrokeredMessage class has several useful properties, including the Properties property, which stores a collection of name-value pairs for persisting properties that are added to the message. This allows for easy management and retrieval of message metadata.
The MessageId property provides a unique identifier for each message, which is useful in searching for a specific message or detecting duplicate message consumption. The SessionId and CorrelationId properties both provide a way to group messages, so a consumer can filter on a given session or correlation.
Sources
- https://k21academy.com/microsoft-azure/az-303/azure-service-bus/
- https://dev.to/willvelida/working-with-queues-and-topics-in-azure-service-bus-279i
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-queues-topics-subscriptions
- https://www.codemag.com/article/1112041/Introducing-Queues-and-Topics-in-Azure-Service-Bus
- https://turbo360.com/blog/azure-service-bus-queues-vs-topics
Featured Images: pexels.com