Monday, February 22, 2010

Technology Review: NServiceBus

This week I'll do the first in the Technology Review series. In this article I'll give you an overview of an open source service bus framework for .Net called NServiceBus. The man behind this framework is Udi Dahan, a well known name in the industry. You can find it at http://www.nservicebus.com/. So let's start with the intro.

1. Introduction to NServiceBus

Like I said, NServiceBus is an open source enterprise service bus implementation in .NET. If you're not familiar with the concepts around enterprise service bus, service bus architecture or service oriented architecture, I'll try to give you a brief introduction here. But I do encourage you to read up on these topics as this will be a very high-level description.

Enterprise service bus is an architecture that allows distributed message exchange between applications or services while at the same time offering the loose coupling of these services by providing facilities such as message routing, reliability and failover and supporting different message exchange patterns such as publish/subscribe, request/response etc.

The backbone of every service bus implementation is the communication/reliability infrastructure i.e the queuing infrastructure. NServiceBus is written for MSMQ, Microsoft queuing service on the Windows Server platform.

So, what do you do with this framework? In essence, you build communicating services on top of it. An example would be services in support of an online store such as ordering, billing, manufacturing, shipping etc.

2. Features

The core features of NServiceBus are the messaging capabilities. These include the publisher/subscriber and request/response message exchange patterns. Pub/sub support also allows you to manage the subscriptions and persist them in a built-in subscription store such as database or MSMQ, or implement your own. Request/response support allows you to use addressing to route messages to specific recipients and to send responses to the originators of the request.

It also supports a long-running message exchange pattern called a saga. A saga is essentially a long-running, persisted, message exchange protocol between services. You can think of it as service orchestration.

The messages that are sent over the bus can be implemented as .NET classes or interfaces.

Besides the core features, NServiceBus also allows for high configurability, building and wiring up objects using a dependency injection framework from an XML config file.

Along with the framework come a few utilities to help you get started. These include the generic host process for message handlers and the distributor utility used for load balancing.

3. API

The central interface in the NServiceBus API is IBus. This is your entry point to start messaging over the bus. IBus interface has methods that support all message exchange capabilities:
  • Publish - publishes a message on the bus
  • Send - sends a message to the destination
  • Reply - replies with a message to the sender
  • Subscribe - subscribes to a message
All of the methods on IBus are templated by the message type.

The main interface for message handlers is IHandleMessage, templated by the message type T. IHandleMessage derives from IMessageHandler which has one method, Handle. Implementers perform message handling in this method.

To start sending messages you need to get an instance of IBus. This is done with dependency injection. Based on the endpoint configuration in the config file, NServiceBus will build up an IBus object and inject it into your endpoint configuration object.

When it comes to configuring enpoints, you have a choice of a few built-in classes to derive from, AsA_Publisher for instance provides the endpoint configuration for a message publisher. The dependency injection is typically done based on the configuration in the XML config file. There you would configure the MSMQ transport properties such as the name of the queue, number of worker threads etc., as well as for clients the mapping of message types to queues.

When it comes to saga support, NServiceBus comes with a Saga base class, templated by the saga data type. Saga data type contains the data about the state of the long-running message exchange orchestration process.

4. Usability

This is where I have a slight issue with this framework. While the design is very clean and abstracted, the API takes getting used to. You definitely don't want to give this to a junior developer.

It relies heavily on dependency injection to bootstrap the core objects and configuration and it is not super-clear what's happening behind the scenes. For instance, you always get the IBus object from DI, and what it does internally is it scans the assembly for types that implement certain marker interfaces to perform the wire-up.

There's quite a bit of friction, too. For instance, the pub/sub example implements the endpoint configuration for a publisher by inheriting from AsA_Publisher, and implementing IConfigureThisEndpoint and ISpecifyMessageHandlerOrdering (last one being optional and used to specify the ordering). IConfigureThisEndpoint is a marker and it isn't very clear what its purpose is, until you read the documentation.

Similar concerns go for the IWantToRunAtStartup interface. Implementers of this interface are invoked on startup, if hosted in the utility host process and they are created using DI.

Another interesting thing in the design of the API in NServiceBus is the message handler interface IHandleMessage. It itself defines no operations, simply derives from IMessageHandler which defines the Handle operation.

Messages as interfaces feature is interesting and I would argue perhaps unnecessary. Allows you to define the message type as a .NET interface and use the CreateInstance method of the IBus interface to create it. CreateInstance doesn't allow for immutable interfaces for messages as message properties are assigned either from an action passed in or after the fact.

The saga support, again, a little weird. Using the base Saga class creates tight coupling with the framework. I would rather have seen a marker and dependency injection to provide the base implementation as an object.

5. Overall Rating

I'm not s huge fan of MSMQ. So, just based on that, I can't in clear conscience give a super-high rating to this framework. Not that it has anything to do with the quality of NServiceBus. But in general, MSMQ as an enterprise queuing infrastructure is at least questionable.

On one hand, the wide scope of various message exchange patterns supported make it a really good candidate for implementing a generic ESB solution. If you need a framework that can withstand change in your environment, be it introduction of new services or new messaging patterns, it is well suited. All the little utilities that are supposed to make hosting solutions based on it easier I feel actually make manageability worse, so this should be a consideration too. Not to mention issues around OS-level security and MSMQ configuration.

There's somewhat of a learning curve with NServiceBus, especially if you're new to concepts such as dependency injection, reflection, extension methods, generics. From that standpoint it isn't too well suited for a small-scale Q&D type project.

Here are my scores for NServiceBus:

Features: 7/10
Quality: 8/10
Usability: 5/10

6. Conclusion

I hope this review helps in choosing the right solution for your application. Keep in mind the other considerations you need to make, like cost, risks, technology and architectural alignment etc.

2 comments:

  1. Thanks for taking the time to write up this review. Just so you know, there is no requirement to inherit from Saga - it just has some utility methods on top of ISaga. Also, MSMQ can be swapped out quite easily.

    ReplyDelete