message oriented architecture using nservicebus
DESCRIPTION
These slides are from my presentation on the benefits and disadvantages of moving from a remote procedure call type of architecture and to a message oriented architecture by using NServiceBus.TRANSCRIPT
Message Oriented Architectureusing NServiceBus
Lars-Erik KindbladSenior Consultant
Twitter: @kindbladE-mail: [email protected]
What is NServiceBus?
Lightweight messaging framework for designing distributed systems in .NET
An Enterprise Service BusHelps to make distributed systems more
Reliable Scalable Extensible
Founded in 2006 by UDI Dahan, an international renowned expert on software architecture and design
Services and support provided by Particular SoftwareOpen Source but not free
Source code available at https://github.com/Particular/NServiceBus
Binaries available as NuGet packages
Remote Procedure Call (Request/Response)
Order ServicePlaceOrder(order)
Request: Order
Website Response: Order ID
Synchronous – The website is blocked while calling the Order Service
Message: PlaceOrderWebsite
Asynchronous – The website is NOT blocked while the place order is processed
Message Queue
Windows ServiceProcess the PlaceOrder message
ConnectReceivePlaceOrder message
Messaged Oriented Architecture (One-way messaging)
NServiceBus Terminology & Components
Message: PlaceOrderWebsite Message Queue
Windows ServiceProcess the PlaceOrder message
ConnectReceivePlaceOrder message
Sender/Send-Only Endpoint
Message,Command or Event
Worker Endpoint,Host or
Receiver
Message Handler
Messages in NServiceBus
Just simple .NET classes with properties
2 types of messages Command
• Do something: PlaceOrder
• Sent from one or more senders, processed by one endpoint
• Implement ICommand
Event• Something has happened: OrderWasPlaced
• Published from one sender, processed by several endpoints/subscribers
• Implement IEvent
Command
Event (Publish/Subscribe)
Command: PlaceOrderWebsite Message Queue Endpoint
Command: PlaceOrder
Event: OrderWasPlacedWorker Message Queue Subscribing
Endpoint
Event: OrderW
asPlaced
Subscribing Endpoint
Subscribing Endpoint
Event: OrderWasPlaced
Event: OrderWasPlaced
Loosely coupled to the receiving
endpoints
Strongly coupled to the receiving
endpoint
NServiceBus will add 3 messages to the queue, one for each subscriber
Queues
First in-first out datastructure for storing and retrieving messages
Queue
PlaceOrder message 4
PlaceOrder message 3
PlaceOrder message 2
PlaceOrder message 1
Default queue in NServiceBus is Microsoft Message Queuing (MSMQ) Available on all Windows editions since NT 4 and Windows 95
Also support for ActiveMQ RabbitMQ SQL Server Windows Azure Queues Windows Azure ServiceBus
One endpoint has one queue, Send-Only endspoints do not have queues
First-In
First-Out
How to Send & Handle Messages
Command: PlaceOrderWebsite Message Queue Endpoint
Command: PlaceOrder
Send Handle (Command or Event)
Summary
Sender endpoint Sends a message Can be a website, desktop application or even a worker endpoint
Command Message where we want to do something concrete ICommand interface
Event Message where we notify about something that has happened IEvent interface
Message handler Processes a given message IHandleMessages<Message> interface
Worker endpoint Finds and executes the handler for the message Can be a Windows Service, console application, WCF, website
NServiceBus Requirements
MSMQ (default) or any other supported queue ActiveMQ RabbitMQ SQL Server Windows Azure Queues Windows Azure ServiceBus
Distributed Transaction Cordinator (DTC)RavenDB (default) or a relational database
Download the installer from NServiceBus from http://particular.net/ to setup the required components
NuGet packages
NServiceBus Interfaces Interfaces that we need to define messages
NServiceBus Most of the code that drives NServiceBus except hosting Use for send-only endpoints
NServiceBus Host Console application that can be installed as a Windows Service Used to process/handle messages
NServiceBus Testing Framework for testing NServiceBus endpoints
The Case – The eBook Shop
1. Create the order in the database
2. Auto-pay the order using a previously stored credit card
3. Send an order confirmation by e-mail
4. Deliver the book to the Windows Phone device
The Usual Way - Request/Response
OrderController
Place order
Browser Database
PaymentService
DeviceService
Confirmation pagewith order ID
1. Add order
2. Charge credit card
4. Deliver ebook
SMTP-Server
3. Send mail
Problem #1 – The order is lost during an error
Conseqence The database is rolled back User receives an error Order must be sent again
OrderController
Place order
Browser Database
PaymentService
DeviceService
Error page
1. Add order
2. Charge credit card
4. Deliver ebook
SMTP-Server
3. Send mail
ErrorException
Problem #2 – Poor Transaction Management
Conseqence: The credit card is charged (no transaction support) A mail saying the order was successful was sent (no transaction support) The order do not exist in the database (supports transaction – rolled back) The user will receive an error
OrderController
Place order
Browser Database
PaymentService
DeviceService
Error page
1. Add order
2. Charge credit card
4. Deliver ebook
SMTP-Server
3. Send mail
ErrorException
New
Let’s Fix This With NServiceBus
Change to a message oriented architecture
OrderController
Place order
Browser
Confirmation page
Add PlaceOrdermessage
Queue
Old
The Message Must Also Be Processed
MSMQ
Worker(Windows Service)
1. Connect 2. Receive message PlaceOrder
3. PlaceOrderMessage Handler
PlaceOrder
Database
PaymentService
DeviceService
4. Add order
5. Charge credit card
7. Deliver ebook
SMTP-Server
6. Send mail
When an Error Occur
MSMQ
Worker(Windows Service)
1. Connect 2. Receive messagePlaceOrder
3. PlaceOrderMessage Handler
PlaceOrderError
4. Rollback. Put the message back on the queueand retry
Server A
More about MSMQ
Max 4MB message sizePersists messages to files. Default location C:\WINDOWS\System32\msmq\storage
Guranteed once-and-only-once delivery The message will only be handled once
Supports transactional queues and distributed transactions (using DTC) If an error occur both changes to the database and to the queue can be rolled back
Supports store-and-forward MSMQ will store messages locally before forwarding it to the queue on another server MSMQ will confirm when the message has been written to the disk in the outgoing queue,
not when it has been delivered to the server Important feature for distributed systems with unrealiable networks
MSMQOutgoing
queueSender
Server B
WorkerMSMQ
Input queue
Message
How NServiceBus Handles Failure
Transaction management and rollback are automatically handled by NServiceBus in message handlers
When an error occur1. The message is put back on the queue
2. Attempt to process the message 5 times, wait for 10 seconds
3. Attempt to process the message 5 times, wait for 20 seconds
4. Attempt to process the message 5 times, wait for 30 seconds
5. Attempt to process the message 5 times, send the message to an error queue
The time interval is configurable
Messages can be moved back to the original queue for replay using ReturnToSourceQueue.exe tool.
A challenge – The Order ID
The order ID has not been generated yet – it’s generated in the message handler at the worker endpoint
NewOld
Possible Solutions
Change the UI to not show the order ID Use a GUID (Guid.NewGuid()) or find another way to generate the ID in the controller
instead of in the database• message.OrderId = Guid.NewGuid();
Bus.Send(message);ViewBag.OrderId = message.OrderId;
• 5773DD0E-0AB0-446B-8649-B2D43D7DA4AA is not a very user friendly ID
Move OrderRepository.Add(order) to the Controller:• var orderId = OrderRepository.Add(order);
Bus.Send(message);
• Less reliable and more error prone solution
Use Send/Reply to simulate request/response• The controller will wait for a PlaceOrderCompleted message that the PlaceOrder handler will send
• Too much overhead
• An Anti-pattern
We Still Have Poor Transaction Management
Conseqence: The credit card is charged (no transaction support) A mail saying the order was successful was sent (no transaction support) The order do not exist in the database (supports transaction – rolledback) The message is put back on the queue and will be retried = credit card will be charged
twice
Handle PlaceOrder Database
PaymentService
DeviceService
1. Add order
2. Charge credit card
4. Deliver ebook
SMTP-Server
3. Send mail
ErrorException
Solution
Split into man small messages - One message per transactional boundary
OrderController
Place order
Browser
1. Add PlaceOrder message
Queue
2. Handle PlaceOrder
4. Handle SendMail
5. Handle DeliverEbook
PlaceOrder message
Add PayOrder message
PayOrder message
Add SendMail & DeliverEbook message
SendMail message
DeliverEbook message
3. Handle PayOrder
If an error occur only DeliverEbook is affected. The
message will be put back on the queue and retried
Code - The Messages
Code – Message Handlers #1
Code – Message Handlers #2
Yet another transactional issue
The message will be put back on the queue and processed againConsequence: The credit card will be charged more than once
Handle PayOrder
Request
MSMQ
Handle PayOrder message
PaymentServiceRequest: Error
Charge credit cardExternal PaymentGateway
Network error
Processed ok
Payment OK
Solution
Operations should be idempotent Idempotent operations can be run many times without changing the result
Database
Has the order been paid?Use OrderId
Handle PayOrder
Request
MSMQ
Handle PayOrder message
PaymentService
Charge credit cardExternal PaymentGateway
Payment OK
Database
Has the message already been processed?Use order ID or a GUID
Payment OK
Another Challenge – Eventual Consistency
The PlaceOrder message is processed async by another process If it has not gotten processed yet then the new order will not be in the listSolution
Some UI trick? Move the OrderRepository.Add to the controller Make sure the messages are handled fast enough
• Define a SLA on the message to help monitoring
Users clicks on View Order History
Publish/Subscribe
OrderController
Place order
Browser
1. Add PlaceOrder message
Queue
2. Handle PlaceOrder
4. Handle SendMailSubscribes to OrderWasPaid
4. Handle DeliverEbookSubscribes to OrderWasPaid
PlaceOrder command
Add PayOrder command
PayOrder command
Add OrderWasPaid event
OrderWasPaid
OrderWasPaid
3. Handle PayOrderSubscribe to OrderWasPaid
With Publish/Subscribe the Subscribers are loosely coupled
to the publisher
NServiceBus will add 2 messages to the queue, one for each subscriber
Summary
Reads is synchronous and should be request/response Using a queue for synchronous operations gives little value, only overhead
Writes can be asynchronous one-way messaging or eventsThere are no silver bullet – We are always trading one set of problems for
another set of problems
Request/Response Command Event
Reliable X X
Consistency X
Can return ID generated by the database to the sender
X
Automatically retries X X
Full transactional support
X X
Loosely coupled X
Scaling
Scale up Easy to scale up if business processes are split into multiple messages Increase the number of threads in the config – NServiceBus will concurrently process
multiple messages
Scale out Use the Distributor or the Master (Both a distributor and a worker)
The distributor will forward the message to a worker that is ready to process the message
DistributorMSMQ
Worker #1
Worker #2
Worker #3
Message
Message
How the Distributor Works
Distributor:Control Queue
1. Worker:Send I’m ready
message
I’m ready messageDistributor
Store I’m ready message
Storage Queue
I’m ready message
PlaceOrder message Send PlaceOrder message from input
queue No
Any messages in the input queue?
Yes
DistributorInput Queue
1. Website:Send
PlaceOrder message
PlaceOrder message Distributor
PlaceOrder message
Find worker through
message in Storage queue
Other Features
Sagas Long running workflow like processes State is shared between multiple message handlers
Scheduling Send a message every x minute. A handler will handle the message
Unobtrusive mode Use your own ICommand, IEvent etc. to reduce coupling to NServiceBus
Supports Various dependency injection containers Logging frameworks Etc.
++
NServiceBus License & Pricing
Open sourceUsed to be free, but not anymore
Indefinitely license with 1 year maintenance updates• $500 USD per processing core
• $250 USD per sending core
Monthly subscription• $35 USD per processing core
• $17 USD per sending core
Development and testing environments + disaster recovery and passive backups are free
Developers need a license (free) that must be renewed every 3rd month through particular.net
Demo
The information contained in this presentation is proprietary.© 2012 Capgemini. All rights reserved.
www.capgemini.com
About Capgemini
With more than 120,000 people in 40 countries, Capgemini is one of the world's foremost providers of consulting, technology and outsourcing services. The Group reported 2011 global revenues of EUR 9.7 billion.Together with its clients, Capgemini creates and delivers business and technology solutions that fit their needs and drive the results they want. A deeply multicultural organization, Capgemini has developed its own way of working, the Collaborative Business ExperienceTM, and draws on Rightshore ®, its worldwide delivery model.
Rightshore® is a trademark belonging to Capgemini