locked
Is Service Broker the right tool in this scenario RRS feed

  • Question

  • Hello,

    Here is my scenario.  I have existing application, which uses MSMQ to send/receive messages.  The message contains requests to perform certain processing.  The receiving component has logic to look at the incoming messages and decide whether or not kick off the processing.  For example, in some cases the process cannot run because it needs to wait for the previous process to finish.  With MSMQ we can look at the message and if we can't process it yet, leave it in the queue until the next check.  Can we do something like this with Service Broker?  Would it be the right tool for the job under these circumstances?

    Thank you!

    Wednesday, October 31, 2012 1:38 AM

Answers

  • If you're talking about millions or more customers that all at the same time do their requests, then you may start to see somewhat slower responses from service broker. But it is no problem at all to have several thousands of conversations open at any time; at my company we have at least one conversation open per "active" order we have in our system and we have thousands of such "active" orders at any time. Service broker does not keep your conversations in memory, if a message is not actively being processed every conversation is merely an entry in a SQL server table. So the number of conversations should hardly ever be an issue. It is the message volume that you should more worry about: how many requests and answers will these customers send and receive per time frame and how large are those messages they produce.

    The concept of "conversations" in Service broker is a powerful mechanism that helps keeping messages ordered in the communication between a client and a server and vice versa (or better: the initiator and the target service). Every message in a conversation is guaranteed to be delivered at the other end in the order they were sent (unless the order was override by setting a higher priority, but that is different story). "Conversation groups" are a higher level of grouping, they provide a mechanism to identify messages that belong together even if they are in different conversations. For example: think of a service A that receives a request. The service A needs to consult another service B to answer the request. What it does is create a new conversation with service B, giving it the conversation group id of the original request. The request for service B is sent on the new conversation and then service A can go on processing more messages and forget about the original request plus its request for service B. Now when the answer from service B comes back to service A, this answer message will have the conversion group id of the original request, so service A immediately knows which request can now be fulfilled and sends back the answer message to the original request on the original conversation. As you can see the services themselves never wait for an answer: all they do is process an incoming message, send out results or store intermediate results into the database and then go on with the next message. All they ever have to wait for is a new message arriving, and if it takes too long for a message to arrive (for you to decide what is too long, but I usually wait at most 10 seconds), they can just close themselves down to safe resources. Service broker will wake them up again when a new message arrives.

    If you want a perfect implementation of your scenario I'd say to first implement a service that routes the messages into queues dedicated per task (called a "message router" in the book I will refer to later). All the message router does is keeping track of which customer currently performs which task and forwarding the messages appropriately. You can make it so that every customer always has it's own instance of the message router (i.e. is not bothered by other customer's current actions) by calling receive without a "where conversation_group_id = ..." on the first call and on the next calls specify "where conversation_group_id = <value returned by the 1st call>". Service broker will create a new instance whenever a message comes in for which no instance exists yet, and each instance that has been inactive for the maximum wait time will shut it self down (to safe resources).

    Each individual task type will be a separate service, each with it's own queue. Each of these queues can be configured per your wishes: f.e. one that can process only one message at a time, another that can have multiple instances running at the same time.

    A good link to start from for understanding messages, conversations and conversation groups is this page on MSDN.

    For more information I would recommend you to read up on message handling. Many patterns have been described already that will prove very helpful in any environment. Service Broker can help you implement many of such patterns. A very good book about message handling concepts, even though it is not about SB in particular, is "Enterprise Integration Patterns" by Gregor Hohpe and Bobby Woolf from Addison-Wesley: ISBN 978-0-321-20068-6. Not affiliated in any way, I just think it's a very good book ;).


    SQL expert for JF Hillebrand IT BV - The Netherlands.


    • Edited by rrozema Thursday, November 1, 2012 11:19 AM Added link into msdn
    • Marked as answer by Michael_SQL Thursday, November 1, 2012 5:31 PM
    Thursday, November 1, 2012 8:55 AM

All replies

  • Your process needs to call the receive command to actually retrieve a message. Any messages not yet received will be kept in a queue by SQL server until someone decides to receive them. i.e. your process can do it's processing and when it is finished processing one message do the next call to receive the next message. So you don't need to explicitly do anything to throttle the messages coming in or so.

    I think however that you have not given all information about your scenario: from the sounds of it you've got multiple different processing tasks running from the same queue. One thing you can do in this situation is to use separate "conversations" per task type. If you have a look at the receive command you'll see you can specify a conversation group id to receive commands for: if you specify "where conversation_group_id = x" the receive command will only fetch messages for the specified group from the queue; other messages will be left untouched. i.e. if you can identify which message should go to the what processor before sending them to the service, you can make sure that all messages for the same processor are sent on the same conversation, i.e. other processors can continue processing their messages from the same queue while one task is still processing its message. Multiple tasks can share the same queue this way.

    On the other hand: if your process can be run simultanously on the same machine (i.e. your process doesn't have any resource that is exclusivly needed per instance), you can use service broker to make your processes multi tasking: Service broker will automatically (if configured to do so) start multiple instances of your process, so the next message can be processed WHILE the first message is still being processed. This behavior is configured in the queue settings: alter queue / create queue.


    SQL expert for JF Hillebrand IT BV - The Netherlands.


    • Edited by rrozema Wednesday, October 31, 2012 12:57 PM uniquely changed to exclusivly
    Wednesday, October 31, 2012 12:54 PM
  • Thank you for the feedback!  Here is little more information about the business scenario.  Let's say we have multiple customers kicking off various processing commands.  For some of these processes I want to only allow one instance to be running at any given time.  For example, if a customer requested a "Process 1" to be ran, but the previous instance of "Process 1" is still running, I want to "wait" before starting on this next request.  That's why ideally I would like to look at the message in the queue and have the ability to leave it in there and move on to the next one.  For example, let's say I have messages in this order:

    1. Customer A (request to run Process 1)

    2. Customer B (request to run Process 1)

    3. Customer A (request to run Process 1 again, but with different parameters)

    4. Customer C (request to run Process 1)

    I will look at the first message and start Process 1 for Customer A.  Next I will look at the second message and start Process 1 for Customer B.  Next I will look at the third message.  In this case I want to leave this message in the queue, because the Process 1 for Customer A is still running (started by the first message).  I want the ability to move on to message 4 and start Process 1 for Customer C.  Later, when the first instance of Process 1 for Customer A is finished I want the ability to retrieve message #3 and start the process accordingly. 

    Having conversations is an interesting suggestion, however, if I have a lot of customers and a lot of different types of requests, I would have to have a lot of conversations going -- one per customer per request type.  So I am not sure this will be very manageable.

    Once again, I am just trying to get a feel if Service Broker is an appropriate platform to use in this scenario.

    Thank you!

    Wednesday, October 31, 2012 3:57 PM
  • If you're talking about millions or more customers that all at the same time do their requests, then you may start to see somewhat slower responses from service broker. But it is no problem at all to have several thousands of conversations open at any time; at my company we have at least one conversation open per "active" order we have in our system and we have thousands of such "active" orders at any time. Service broker does not keep your conversations in memory, if a message is not actively being processed every conversation is merely an entry in a SQL server table. So the number of conversations should hardly ever be an issue. It is the message volume that you should more worry about: how many requests and answers will these customers send and receive per time frame and how large are those messages they produce.

    The concept of "conversations" in Service broker is a powerful mechanism that helps keeping messages ordered in the communication between a client and a server and vice versa (or better: the initiator and the target service). Every message in a conversation is guaranteed to be delivered at the other end in the order they were sent (unless the order was override by setting a higher priority, but that is different story). "Conversation groups" are a higher level of grouping, they provide a mechanism to identify messages that belong together even if they are in different conversations. For example: think of a service A that receives a request. The service A needs to consult another service B to answer the request. What it does is create a new conversation with service B, giving it the conversation group id of the original request. The request for service B is sent on the new conversation and then service A can go on processing more messages and forget about the original request plus its request for service B. Now when the answer from service B comes back to service A, this answer message will have the conversion group id of the original request, so service A immediately knows which request can now be fulfilled and sends back the answer message to the original request on the original conversation. As you can see the services themselves never wait for an answer: all they do is process an incoming message, send out results or store intermediate results into the database and then go on with the next message. All they ever have to wait for is a new message arriving, and if it takes too long for a message to arrive (for you to decide what is too long, but I usually wait at most 10 seconds), they can just close themselves down to safe resources. Service broker will wake them up again when a new message arrives.

    If you want a perfect implementation of your scenario I'd say to first implement a service that routes the messages into queues dedicated per task (called a "message router" in the book I will refer to later). All the message router does is keeping track of which customer currently performs which task and forwarding the messages appropriately. You can make it so that every customer always has it's own instance of the message router (i.e. is not bothered by other customer's current actions) by calling receive without a "where conversation_group_id = ..." on the first call and on the next calls specify "where conversation_group_id = <value returned by the 1st call>". Service broker will create a new instance whenever a message comes in for which no instance exists yet, and each instance that has been inactive for the maximum wait time will shut it self down (to safe resources).

    Each individual task type will be a separate service, each with it's own queue. Each of these queues can be configured per your wishes: f.e. one that can process only one message at a time, another that can have multiple instances running at the same time.

    A good link to start from for understanding messages, conversations and conversation groups is this page on MSDN.

    For more information I would recommend you to read up on message handling. Many patterns have been described already that will prove very helpful in any environment. Service Broker can help you implement many of such patterns. A very good book about message handling concepts, even though it is not about SB in particular, is "Enterprise Integration Patterns" by Gregor Hohpe and Bobby Woolf from Addison-Wesley: ISBN 978-0-321-20068-6. Not affiliated in any way, I just think it's a very good book ;).


    SQL expert for JF Hillebrand IT BV - The Netherlands.


    • Edited by rrozema Thursday, November 1, 2012 11:19 AM Added link into msdn
    • Marked as answer by Michael_SQL Thursday, November 1, 2012 5:31 PM
    Thursday, November 1, 2012 8:55 AM
  • Thank you very much for such a thorough response!  I appreciate the time you took to provide so many details and will certainly do some more reading using the informaiton you provided.  I hope Netherlands wins the next soccer World Cup! (finally :))
    Thursday, November 1, 2012 5:31 PM