July 1998
Use MSMQ and MTS to Simplify the Building of Transactional Applications
Download msmqmts798.exe (44 KB)
Mark Bukovec is a Program Manager for the Microsoft COM+ team. He has also worked with the ODBC, OLE DB, and MTS teams
while at Microsoft. Dick Dievendorff is a Software Architect working on the Microsoft COM+ team. He also works on enterprise transaction systems and messaging systems.
|
Before the release
of Microsoft® Message Queue Server (MSMQ), programming asynchronous distributed Windows®-based applications was not for the faint-hearted. Not only did you need in-depth knowledge of marshaling to get a client or server to properly queue, send, and receive asynchronous messages, but implementing proper failure recovery in case a message or queue went down was a time-consuming and difficult process. A server failure during the middle of an asynchronous operation could leave work in an ambiguous state. Ensuring that your asynchronous operation either committed or failed and rolled back to the last consistent state meant programming transactional support for your queue (an arduous task at best).
MSMQ, which shipped with the Windows NT® Option Pack (available at http://www.microsoft.com/Windows/downloads/ contents/Products/NT4OptPK), makes asynchronous programming possible for mere mortals. In addition to a simplified asynchronous programming model, MSMQ offers you built-in transactional support so your message queues can participate in Microsoft Transaction Server (MTS) transactions. This means that your asynchronous operations can be rolled into an existing transaction or into a new transaction you create. Not only will you be able to offer the flexibility of asynchronous messages, you can ensure that your data will not be compromised by inconsistent state. That's a pretty compelling argument for using MSMQ. Let's explore how MSMQ simplifies building transactional applications. We'll describe how you can use MSMQ in an MTS application, and then walk you through a sample application that uses a transactional message queue. Finally, we'll talk about the evolution of MSMQ and its integration with MTS. Before you continue (and if you have not already done so), see David Chappell's article in this issue for an overview of MSMQ. We'll assume a general understanding of the concepts of message queuing and MSMQ. Transactional Message Queuing Consider the following scenario. You've just built a distributed application for a pet supply company. Since most of the salespeople are on the road pitching new products, you've accommodated disconnected clients by using asynchronous message queues in your application. A salesperson can use your client app to fill out an order form and submit it for processing while unconnected to the network server. The message is stored in a queue on the client machine. The next time that salesperson connects with the company network, the Order information is uploaded to the server application for processing. Let's say a particularly industrious salesperson has accumulated over 200 orders while crossing two states. The salesperson innocently dials into the company network and sends the messages. The server reads the Orders from the queue and updates an inventory database. Then the main server goes down while this work is happening (as it invariably does in the Se scenarios). Since the asynchronous operations were not wrapped in transactions, the salesperson has no idea which of the Orders were sent through for processing. Someone must then spend a good deal of time making sure that potential customers don't get charged for what they aren't getting shipped. If you had built your application using a transactional message queue, this scenario would have been accounted for and managed. When the company server went down and the asynchronous operation failed, the entire read message operation would have rolled back to its last consistent state. As far as the industrious salesperson is concerned, the Order has been processed. The server can retry the Operation at a later time. the Orders are safe and sound in the queue, so obviously the data was never sent to billing or shipping. The salesperson can send again at a later date, and in the duration, canvass pet stores in another two states. Transactional message queuing is clearly important for maintaining the integrity of your data. It's also important to be able to integrate a message queue seamlessly into your distributed application. Let's take a look at how transactional message queuing combines the benefits of MTS and MSMQ. First of all, if you aren't already using MTS (also available in the Windows NT Option Pack) to build your servers, you're doing a lot more programming than you should. See the sidebar "Scalable Servers with MTS"; for an overview of how MTS allows you to easily scale and deploy your applications. MTS also improves the fault-tolerance of your application through transactions. Transactions are powerful tools for maintaining the integrity of data. (For more information on transactions, see the sidebar "Transactions in Distributed Applications.")
MSMQ and Transactions
This means that each transaction can occur independently. If the client's first transaction commits successfully, then the message is stashed away in an input queue. If the server transaction fails, the transaction rolls back to its last consistent statewhich means that the client's message is still in the input queue. If you had rolled the client send operation and the server processing of the message in one big transaction, then you would have lost the client's message in the rollback. Assuming that your application operates in a disconnected environment, you have to wait until your client gets back online to restart the entire process. MSMQ can also participate in existing MTS transactions as a resource manager. Let's go over how transactions work in a distributed MTS-based application. In a distributed environment, an application partitions its work among multiple components. How is it possible to put the work of two different components into a single transaction when each component is committing its own updates to a different database? You need to have a transaction manager to coordinate all that traffic. MTS and MSMQ use the Microsoft Distributed Transaction Coordinator (MS DTC). MS DTC oversees the two-phase commit protocol. Let's consider an example in which MS DTC is coordinating a two-phase commit with two resource managers, MSMQ and SQL Server. In the first phase, MS DTC issues a "prepare to commit" message to both MSMQ and SQL Server. The resource managers participating in the transaction make the results of the transaction durable but do not actually commit the transaction. MS DTC then waits for MSMQ and SQL Server to report that they have prepared the transaction before continuing to the second phase of the commit protocol. During the second phase, MS DTC tells MSMQ and SQL Server to commit their transactions. Only when both resource managers have reported that they have successfully committed their transactions can the distributed transaction be committed. For the low-level view on how MSMQ interacts with MS DTC in a distributed transaction, read the Microsoft OLE Transactions specification. If you're programming for MSMQ, though, all you need to know is that MSMQ enables you to roll your messaging operations in a transaction as well as participate in existing transactions managed by MS DTC.
MSJQueue
|
Figure 1 MSJQueue Client and Server Sample |
MSJQueue Client and Server
Setting Up and Deploying MSJQueue
|
Figure 3 MSJQueue Package in MTS Explorer |
|
Figure 4 Message Processing in a Transaction |
"Transaction required" means that when an object instance is created, it will be part of the creator's transaction. If the creator is not transactional, a new transaction is started for the created object. In our application, QueueServer is not a transactional component; it is not an MTS component at all. QueueServer is considered the base client. MTS defines base clients as the primary consumers of MTS objects, although base clients execute outside of the MTS runtime environment. |
Figure 5 Creating a Queue in MSMQ Explorer |
Sending and Receiving Messages Using MSMQ Queues
Finding a Queue
Opening a Queue for Sending a Message
Transactional Message Queues
The request queue on the client is handled on our behalf by MSMQ. Therefore, our transaction spans sending the message from the client to the server and implicitly includes the request queue. Our application does not use a client-side response queue. A response queue would receive acknowledgment messages from the server indicating that the request message has been read from the queue and the transaction has been processed.
Sending a Message
|
Figure 8 An MSJQueue Message |
|
Figure 9 MSJQueue Messages |
|
Figure 10 The Contents of an MSJQueue Message |
QueueServer
Processing the Message
The Future
From the July 1998 issue of Microsoft Systems Journal.
|