The Technical Blog
Azure Queue Storage vs. Azure Service Bus
Mon 17-Feb-2020 09:44 PM +00:00
TL;DR: Always choose Service Bus.
I'll be honest, this isn't going to be close. I've used both, and while they both sort-of do the same thing, Azure Service Bus has so many more features for each message, and is now cheaper at higher volumes, that there's no reason to use Azure Queue Storage for a production application unless you have low message volumes and want to save less than $10/month.
Azure Queue Storage
Here's the thing: Azure Queue Storage used to be cheaper, but if you're running General Purpose v2 Storage Accounts, it's not anymore. There are two costs for Queues: storage, and transactions. Since queue messages won't often accumulate much, they won't take up much storage, so that'll be like $0.05/month. For General Purpose V2 storage accounts, Queue messages cost the same as they do for Table and Blob Storage: 10,000 transactions for $0.0040. (The pre-transaction cost is now higher with V2.)
In other words, if you send 10,000 queue messages/day for a month, it'll cost you $1.20. (A message incurs two transactions: one send, one receive).
Azure Service Bus
Azure Service Bus, on the other hand, starts its pricing at $10.00/month for up to 13,000,000 operations, with the next 74M operations billed at $0.20/million, and other rates at higher numbers. (Like Queue Storage, sends and receives both count as operations.)
Pricing comparison (each message counts for two operations)
For low numbers of messages, Azure Queue Storage is cheaper because of the minimum $10.00 cost.
|Messages / Operations||Azure Service Bus||Azure Queue Storage|
|1,000,000 / 2,000,000 (~0.38 msg/sec)||$10.00||$0.80|
|12,000,000 / 24,000,000 (~5 msg/sec)||$12.20||$9.60|
|18,500,000 / 37,000,000 (~7 msg/sec)||$14.80||$14.80||⬅ break-even|
|50,000,000 / 100,000,000 (~20 msg/sec)||$35.20||$40.00|
|250,000,000 / 500,000,000 (~100 msg/sec)||$115.20||$200.00|
|500,000,000 / 1,000,000,000 (~200 msg/sec)||$215.20||$400.00|
The break-even point is about 18.5M messages/month.
So Queue Storage is cheaper at lower message rates, but if you're serious about messaging, whether in terms of volume or features, you want Service Bus.
Speaking of features...
Azure Queue Storage
Uh… um… well, you can definitely send messages up to 64KB using it. Yeah. And you can get up to 2,000 messages/second (i.e. 2,000 transactions/partition in Azure Storage) from each queue.
Azure Service Bus
On the other hand, Azure Service Bus actually has features.
One-to-Many Routing: Topics and Subscriptions
Azure Service Bus has the expected one-to-one routing of Queues. It also has one-to-many routing using Topics and Subscriptions.
Service Bus Topics receive messages just like queues, but then they distribute them to as many Subscriptions as you want. Each Topic can have up to 2,000 Subscriptions, so, you know, that's a lot of fanning out.
One excellent use of this is for sharing overall system status between servers. You could have one well-known Topic that receives all of the updates from all of the servers, and then have each server register itself as the receiver of a Subscription on that Topic. Now every server gets to see all of the status updates from all of the other servers.
The Message, which is the .NET class we use to send and receive messages with Service Bus, has a lot of great features. The first one I want to highlight is the CorrelationId. The CorrelationId is a field you can set with an arbitrary string you use to track an operation all the way through your system. For instance, let's say a client sends an update message to a Service Bus Topic. You might want to have the client generate a GUID that gets put on the message. Your server logic would take that GUID and pass it along with each step in a process, including all logging that takes place on the way. Having it right on the Message instance is very handy, and I've used it to great effect.
Another great feature of Message is the UserProperties property (yeah, I know). This is a simple Dictionary<string, object> that you can use to put any kind of metadata on the message. I've used these properties to hold context about the message; while I passed the serialized payload in the body of the message (so I can deserialize to the same type), I was also able to include information about how to handle the message in Properties without having to change the structure of the data itself.
The Label property lets you assign labels to your messages. This could also be done in Properties, but I like that Label is a first-class property. I think it shows thoughtful design in Service Bus.
When you have to guarantee delivery order of a series of messages, Service Bus has Sessions to help. When you create a Queue or Topic that's session-enabled, every message that has the same SessionId is guaranteed to be delivered in-order.
Every Subscription can have a filter applied to it, to allow it to tell Service Bus which messages to deliver, and which ones not to deliver. The filters look like SQL WHERE clauses, and can save you from seeing messages that you'd rather not see.
A great place to use this is, again, the example of a well-known topic that servers subscribe to in order to communicate with each other. Each subscriber should place a filter on the subscription it sets up to filter out messages sent by themselves... they already know, no need to get the message again.
Choose Azure Service Bus, because duh.
If you really don't care about doing anything but pumping messages through queues, and you're not going to track them, sure, Azure Queue Storage would work absolutely fine. (If you'll blow past 2,000 messages/second, just do sharded queues.) I'd like to add: especially if you don't mind losing a message here and there... not because I think Azure Storage will lose any messages, but because you're giving up your ability to correlate your queue messages all the way through the operation.
But, sigh even then, use Azure Service Bus. If you're at the scale of 2,000+ queue messages/second, you're running a serious system. Just use Service Bus.