Physical routing with MSMQ

Component: MSMQ Transport
NuGet Package NServiceBus (6.x)

The MSMQ transport in NServiceBus is a distributed transport in which there is the MSMQ process running on each machine, with messages being stored locally before being forwarded to other machines. In this model, each endpoint connects to the local MSMQ process and, when addressing a different endpoint, not only the queue name but also the host name has to be specified.

Scaling out

Because the MSMQ queues are not accessible from outside the machine they are hosted at, NServiceBus endpoints using the MSMQ transport are unable to use the competing consumers pattern to scale out with a single shared queue.

Sender-side distribution can be used to overcome this limitation.

Physical mapping

Mapping the logical destination to the physical address containing the queue and host names is the responsibility of physical routing.

The preferred way of configuring the physical routing is via the instance mapping file.

Instance mapping file

The instance mapping file is a simple XML file that has to be located either on a local hard drive or a network drive. When using MSMQ as the transport, NServiceBus will automatically look for an instance-mapping.xml file in AppDomain.BaseDirectory.

When running under ASP.NET the instance-mapping.xml file may not be located in AppDomain.BaseDirectory. In this case specify the path using the FilePath setting.
<endpoints>
  <endpoint name="Sales">
    <instance machine="VM-1"/>
  </endpoint>
  <endpoint name="Shipping">
    <instance machine="VM-2"/>
  </endpoint>
  <endpoint name="Billing">
    <instance machine="VM-3"/>
  </endpoint>
</endpoints>
The endpoint names are case sensitive e.g. if endpoint name is used in routing API and the instance mapping file, the file entries will be used only when there is a case sensitive match.

The mapping file is processed before the endpoint starts up and then re-processed at regular intervals so the changes in the document are reflected in the behavior of NServiceBus automatically. If the document is not present in its configured location when endpoint starts up, NServiceBus will not search again for the file at runtime. If it is deleted when the endpoint is already running, it will continue to run normally with the last successfully read routes.

There are many different options to consider when deploying routing configuration.

  • Many endpoints can be configured to use one centralized mapping file on a network drive accessible by all, creating a single file that describes how messages flow across an entire system. Any given endpoint will not care if the file contains information for endpoints it does not need.
  • The mapping file can be kept in a centralized location and replicated out to many servers on demand, allowing each endpoint to read the file from a location on the local disk.
  • Each endpoint can keep its own instance mapping file containing only information for the endpoints it needs to know about, which can be deployed in the same directory as the endpoint binaries and only modified as part of a controlled deployment process.

The following default settings can be adjusted:

RefreshInterval

Specifies the interval between route data refresh attempts.

Default: 30 seconds

var transport = endpointConfiguration.UseTransport<MsmqTransport>();
var routing = transport.Routing();
var instanceMappingFile = routing.InstanceMappingFile();
var fileSettings = instanceMappingFile.FilePath(@"C:\instance-mapping.xml");
fileSettings.RefreshInterval(TimeSpan.FromSeconds(45));

FilePath

Specifies the path and file name of the instance mapping file. This can be a relative or an absolute file path. Relative file paths are resolved from AppDomain.BaseDirectory.

Default: instance-mapping.xml

var transport = endpointConfiguration.UseTransport<MsmqTransport>();
var routing = transport.Routing();
var instanceMappingFile = routing.InstanceMappingFile();
instanceMappingFile.FilePath(@"C:\instance-mapping.xml");

Custom instance mapping

Physical routing is responsible for mapping the destination logical endpoint to the transport address (queue name).

The instance mapping aspect of routing, as well as all other aspects, can be customized if the standard built-in file-based mapping is not feasible (e.g. in elastically scaled-out environments).

protected override void Setup(FeatureConfigurationContext context)
{
    var endpointInstances = context.Settings.Get<EndpointInstances>();
    endpointInstances.AddOrReplaceInstances("MySource",
        new List<EndpointInstance>
        {
            new EndpointInstance("MyEndpoint").AtMachine("VM-1"),
            new EndpointInstance("MyEndpoint").AtMachine("VM-2")
        });
}

The source parameter has the same meaning and effect as in the routes collection.

The instances collection is thread-safe. It allows registering multiple instance of a given endpoint. In case there is more than one, message distribution is involved.

Using message-endpoint mappings

For compatibility reasons it can also be configured in the same way as in Version 5 and older by UnicastBusConfig/MessageEndpointMappings configuration section:

<configuration>
  <configSections>
    <section name="UnicastBusConfig"
             type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core"/>
  </configSections>
  <UnicastBusConfig>
    <MessageEndpointMappings>
      <add Assembly="Sales.Messages" 
           Endpoint="Sales@VM-1" />

      <add Assembly="Billing.Messages"
           Endpoint="Billing@VM-2" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
</configuration>
The downside of this approach is that it mixes logical and physical concerns. It also does not allow to configure more than one endpoint instance as a destination which prevents scaling out via sender-side distribution.

Related Articles


Last modified