Azure Service Bus: Count your filters

TL;DR: Azure Service Bus can publish one message to a topic and deliver it to multiple consumers. A topic is the shared destination, a subscription is a consumer-specific view, and a filter decides whether a message is copied to that subscription. In high-throughput systems, the number of subscription rules can matter more than the filter type itself.

This is the first post in a short series on Azure Service Bus topology under load. The series looks at filter count, subscription fan-out (one message reaching several subscriptions), topic depth (messages waiting in a topic), blast radius, and migration strategy. This one focuses on the cost of filter evaluation. If topics and subscriptions are new to you, start with Microsoft’s overview of topics and subscriptions.

Here is the basic model for the rest of the series. A publisher sends a message to a topic. Each subscription provides an independent delivery view for a consumer, and a filter determines whether the message is stored in that subscription. The set of topics, subscriptions, filters, and forwarding rules is the messaging topology.

I like broker features that let application code stay simple. Azure Service Bus topic filters are one of those features. Publish a message once, let the broker evaluate subscription rules, and deliver the message to the subscribers that care about it.

The application stays simple, but the broker still has to evaluate every rule. Once a topic has many subscriptions and each subscription has many rules, every published message creates more routing work.

What does a filter cost?

Azure Service Bus supports SQL filters, boolean filters, and correlation filters on topic subscriptions. Boolean filters are the simple TrueFilter and FalseFilter cases; the default rule on a new subscription is a TrueFilter, which matches every message until you replace it. SQL filters provide a richer expression language with relational operators, property existence checks, and text pattern matching with LIKE. Correlation filters express equality-style matching over system and user-defined properties and are generally the more efficient option when the routing condition can be represented that way.

SQL filters get attention because they are expressive. Microsoft Learn’s performance guidance notes that complex filter rules require processing capacity. Rule count matters just as much. One SQL filter and one hundred correlation filters create very different workloads because the broker evaluates routing rules for every published message.

Pay particular attention to a shared topic where each logical subscriber owns a subscription, and each subscription contains one rule per event type or one rule per type in an event hierarchy. This design has only one topic to manage. It also puts all routing work on that topic.

Rule actions also change the delivery result. Azure Service Bus combines rules without actions using an OR condition and produces a single message on the subscription even if multiple rules match. Each matching action rule produces a separate annotated copy. Rule design affects both routing and duplication semantics.

Compare the same workload

I compare these topologies with the same Azure Service Bus resource budget and ask how much useful work each one can handle.

The workload behind the examples comes from my AzureServiceBusTopologyComparison repository. It is a small .NET and Helm harness for running controlled comparisons. The publisher emits a controlled stream of messages, including a configurable event-type hierarchy. The subscriber provisions the selected topics, subscriptions, filters, and forwarding paths, then consumes from input queues. The Helm configuration varies event ranges and subscriber groups.

The repository generates the workload and topology. The CPU, memory, throttling, and topic message count charts come from Azure Monitor while those workloads run. The results in this series describe these configurations and resource limits.

For broker topology work, I prefer fixed-resource tests. Use one Premium Messaging Unit (MU), the dedicated compute and memory allocation in the Premium tier. Keep the incoming event rate stable. Watch CPU, memory, throttling, outgoing rate, and topic depth. I use “topic depth” as shorthand for the topic message count metric: the number that tells me whether messages are accumulating under steady load.

These fixed-resource tests compare how topology shapes behave under the same workload and Premium Messaging Unit budget. Their numbers are specific to that setup.

In the tests that shaped my thinking here, messages carried a type hierarchy. A two-level hierarchy created fewer subscription rules. A three-level hierarchy created more. A four-level hierarchy created more again. That one variable was enough to expose the cost of subscription rule count.

Topology shapeWhat changed as hierarchy depth grew?
SQL filters on a shared topicCPU usage rose sharply, and topic depth became less stable at higher subscription rule counts.
Correlation filters on a shared topicLower cost than SQL filters in smaller cases, but higher subscription rule counts still increased pressure.
Topic per event typeNo filter evaluation on the shared hot path, so the routing work stayed much flatter.

The pattern matters more here. Correlation filters helped when the subscription rule count was low. Once the topology needed many filters, the rule count became the main scaling factor.

One four-level correlation-filter test kept incoming traffic steady while topic message count grew. The chart illustrates why a successful send is not the same as a stable topology.

Why inheritance makes this easy to miss

Event inheritance can make filter count grow quietly. Suppose a published event has a concrete type and three interfaces in its hierarchy. If a subscriber can subscribe to any of those types, the topology may need routing rules for each type in that hierarchy.

Concrete event: Sales.OrderAccepted
Interface:      Sales.IOrderAccepted
Interface:      Sales.IOrderEvent
Interface:      NServiceBus.IEvent

That is not a strange model. It supports useful polymorphic routing. The catch is that the broker has to evaluate the subscription rules that make the model work. If many endpoints subscribe to many event types, and each event type carries several hierarchy entries, the subscription rule count can grow faster than the team expects.

Azure Service Bus also has quota differences between filter types. As of February 2026, the Azure Service Bus quotas page lists up to 2,000 SQL filters and 100,000 correlation filters per topic. A correlation filter match is equality-based and string comparisons are case-sensitive. Those limits describe the largest supported configuration, not its runtime cost. A topology can become expensive before it reaches a quota.

What should you measure?

Comparing SQL filters with correlation filters is useful, but for high-throughput pub/sub workloads I would count the rules first:

  • How many subscriptions does the topic have?
  • How many subscription rules does each subscription carry?
  • How many rules does each published message need to be compared against?
  • Does topic depth stay flat under load?
  • Does CPU rise with event hierarchy depth?

These questions make filter count an operational metric the team can watch before the namespace starts throttling.

Count the rules

Azure Service Bus filters are good tools. SQL filters are useful when routing needs expressive conditions. Correlation filters are useful when equality matching is enough. Neither choice removes the need to count the rules.

SQL filters are not inherently a design smell. The problem is losing track of how many rules each message encounters. If every message enters a shared topic and every subscription has many rules, the broker still has to do that routing work. Avoiding an evaluation is cheaper than performing one.

Further reading:

Common questions

Before changing an existing Azure Service Bus topology, I would start with these questions.

Should I avoid SQL filters completely?

No. SQL filters are useful when the routing condition needs their expression language. Use them deliberately and measure the cost when they sit on a high-volume topic.

Are correlation filters always enough?

No. They are a better fit for simple equality matching, but they do not make the subscription rule count disappear. A large number of correlation filters can still put pressure on a topic.

What should I remember?

Count subscription rules as part of the topology because that configuration creates runtime work.

About the author

Daniel Marbach

Add comment

Recent Posts