Multiple namespace support

Component: Azure Service Bus Transport
NuGet Package NServiceBus.Azure.Transports.WindowsAzureServiceBus (7.x)
Target NServiceBus Version: 6.x

Azure Service Bus transport supports configuring multiple Azure Service Bus namespaces, in order to:

  • Enable various namespace partitioning strategies to cover scenarios such as High Availability and multiple Data Center support, or to overcome Azure services limits.
  • Enable cross namespace routing to endpoints outside of the partition set.

The namespace partitioning strategy can be configured using the NamespacePartitioning() configuration API section, where the cross namespace routing can be configured using the NamespaceRouting() API section. NServiceBus provides a few namespace partitioning strategies implementations. It's also possible to implement a custom partitioning strategy if needed.

Using multiple namespace is currently NOT compatible with ServiceControl. A ServiceControl transport adapter or multiple installations of ServiceControl is required in order to leverage both.

Single namespace partitioning

By default the Azure Service Bus transport uses the SingleNamespacePartitioning strategy, when it is configured using the ConnectionString extension method:

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
transport.ConnectionString(
    connectionString: "Endpoint=sb://[NAMESPACE].servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");

This is the functional equivalent of providing a namespace using the AddNamespace partitioning API with the default namespace alias and namespace's connection string.

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
var partitioning = transport.NamespacePartitioning();
partitioning.UseStrategy<SingleNamespacePartitioning>();
partitioning.AddNamespace(
    name: "default",
    connectionString: "Endpoint=sb://[NAMESPACE].servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");

With this strategy, the transport uses only a single namespace to send and receive messages, hence only one namespace can be configured for the purpose of partitioning. When more than one namespace, or none, is specified for partitioning, then a ConfigurationErrorsException will be thrown at startup.

Round robin namespace partitioning

The RoundRobinNamespacePartitioning can be used to avoid throttling by the service. With this strategy, the transport uses multiple namespaces for the communication between endpoints. Messages are sent to a single namespace and received from all namespaces. For sending operations, namespaces are chosen in a round-robin fashion.

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
var partitioning = transport.NamespacePartitioning();
partitioning.UseStrategy<RoundRobinNamespacePartitioning>();
partitioning.AddNamespace(
    name: "namespace1",
    connectionString: "Endpoint=sb://namespace1.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");
partitioning.AddNamespace(
    name: "namespace2",
    connectionString: "Endpoint=sb://namespace2.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");
partitioning.AddNamespace(
    name: "namespace3",
    connectionString: "Endpoint=sb://namespace3.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");

Multiple namespaces have to be configured when using RoundRobinNamespacePartitioning strategy. When less than two namespaces are specified, then a ConfigurationErrorsException will be thrown at startup.

Fail over namespace partitioning

The FailOverNamespacePartitioning can be used to provide High Availability. It uses two different namespaces: a primary and a secondary. The transport uses the primary namespace by default, and switches to secondary one when the primary is not available.

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
var partitioning = transport.NamespacePartitioning();
partitioning.UseStrategy<FailOverNamespacePartitioning>();
partitioning.AddNamespace(
    name: "primary",
    connectionString: "Endpoint=sb://primary.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");
partitioning.AddNamespace(
    name: "secondary",
    connectionString: "Endpoint=sb://secondary.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");

Exactly two namespaces have to be configured when using FailOverNamespacePartitioning strategy. When only one or more than two namespaces are specified, then a ConfigurationErrorsException will be thrown at startup.

Cross namespace routing

NServiceBus allows to specify destination addresses using an "endpoint@physicallocation" in various places such as the Send and Routing API or the MessageEndpointMappings. In this notation the physicallocation section represents the location where the endpoint's infrastructure is hosted, such as a machine name or a Service Bus namespace.

Using this notation it is possible to route messages to any endpoint hosted in namespaces that do not belong to the current endpoint's partition set.

endpointInstance.Send(
    destination: "sales@Endpoint=sb://destination1.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]", 
    message: new MyMessage());

Versions 7 and above of the Azure Service Bus transport it is also possible to provide an alias for namespaces, and use alias instead of connection string value; in all of these places.

endpointInstance.Send(
    destination: "sales@destination1", 
    message: new MyMessage());

This requires namespace alias and connection string to be registered using the NamespaceRouting() API.

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
var routing = transport.NamespaceRouting();
routing.AddNamespace(
    name: "destination1",
    connectionString: "Endpoint=sb://destination1.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");
routing.AddNamespace(
    name: "destination2",
    connectionString: "Endpoint=sb://destination2.servicebus.windows.net;SharedAccessKeyName=[KEYNAME];SharedAccessKey=[KEY]");

Default namespace alias

When using the ConnectionString method to configure a namespace, it will get an alias as well. This alias is represented by the DefaultNamespaceAlias configuration setting, which has a value of default.

When doing cross namespace request reply communication between endpoints configured this way, in combination with the UseNamespaceAliasesInsteadOfConnectionStrings() configuration method to secure connection strings, then the reply address header will include a value of "sourceendpoint@default". However, the connection string that is mapped to this alias is different for each endpoint in the communication and it will break the request-reply pattern.

In order to overcome this problem, it is possible to change the value of the DefaultNamespaceAlias configuration setting using the API:

var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
transport.DefaultNamespaceAlias("myalias");

or use NamespacePartitioning().AddNamespace() with a different alias instead of the ConnectionString() method in the source endpoint.

And ensure that the same alias and connection string are registered with the replying endpoint using the NamespaceRouting().AddNamespace() method.

Samples


Last modified