Programming Distributed Transactions

[Previous] [Next]

As you've seen, a single DBMS can enforce the ACID rules when it holds all the data involved in a transaction. For example, SQL Server supplies an internal transaction manager that provides commit and rollback behavior. The transaction manager also guarantees that committed data is recoverable in the event of a system failure.

But what happens if not all the data involved in a transaction resides on the same computer or in the same database format? OLTP applications that run such distributed transactions are far more challenging to implement. Imagine a situation in which the Products table is in a SQL Server database, the Customers table is in an Oracle database, and the Orders table is in DB2, as shown in Figure 8-3. To run a distributed transaction, you must use software that coordinates commit/abort behavior and recovery across several data sources at once.

click to view at full size.

Figure 8-3 A transactional application and transaction managers work together to monitor a distributed transaction and to execute the two-phase commit protocol across multiple resource managers.

Quite a few software products use a similar high-level architecture to solve the problems associated with running distributed transactions. For example, CICS from IBM, Tuxedo from BEA Systems, and COM+ from Microsoft all use a high-level abstraction called a transaction manager (TM) and a special protocol called two-phase commit.

Much of the terminology related to distributed transactions was coined in the early days of CICS. The application that performs the read/write operations and ultimately controls the transaction is known as a transactional application. Each data source is known as a resource manager (RM). Each node (computer) in the system either runs a local session of a TM or communicates with a remote session of a TM. An application that's built on top of this infrastructure is often called a transaction monitor.

To see things in a clearer light, let's examine how these different applications and services interact. A transactional application calls a TM and makes a request to start a distributed transaction. The TM creates a transaction by generating a unique ID and initializing various data structures to manage the transaction's lifetime. This TM is in charge of running the two-phase commit protocol and is known as the coordinating transaction manager (CTM).

In addition to calling the TM to start a distributed transaction, a transactional application also enlists connections to one or more RMs. This enlistment process involves passing the distributed transaction's ID to an RM and telling the RM to subordinate control of the transaction to the CTM.

In some deployments, an enlisted RM communicates directly with the CTM. In other deployments, an RM enlists with a local TM, which is known as a participating transaction manager (PTM). During this type of enlistment, the CTM must also establish a connection with the PTM. Once each connection has been enlisted, the lines of communication are set up as shown earlier in Figure 8-3.

The transactional application and the CTM work together to enforce the ACID rules across the entire transaction. The transactional application issues commands to the CTM, and the CTM coordinates commit/abort behavior across the entire group of participants.

The CTM enforces the ACID rules in a distributed transaction by running the two-phase commit protocol. After the transactional application indicates that it wants to commit the transaction, the CTM runs phase 1 to prepare the transaction. In this phase, the CTM sends an "Are you prepared?" message to each participant. If everything goes according to plan, each participant responds with an "I'm prepared" message.

By responding with an "I'm prepared" message, an RM indicates that its changes are in a durable state and that it can either commit or roll back those changes on request. Once every participant has responded with an "I'm prepared" message, the CTM knows that the changes can be committed, and the CTM can complete phase 1.

Here's what happens at the end of phase 1 in a successful transaction. After receiving an "I'm prepared" message from each participant, the CTM writes to its log that the transaction has been committed and returns a successful response to the transactional application. At this point, the transactional application is free to start other work, and the locks acquired by the transaction are still being held.

In phase 2, the CTM sends a "Time to commit" message to each participant. When an RM receives such a message, it's free to release the locks and discard any residue required to roll back the transaction. After committing its changes, each RM sends an "I'm done" message to the CTM. Once the CTM receives this message from every participant, it assumes that all the work has been successfully completed and that it, too, can discard any residue required to roll back the transaction.

As a programmer building COM+ applications, you don't have to be overly concerned with the inner workings of the two-phase commit protocol, which is really just an implementation detail. When you commit a distributed transaction in COM+, you should assume that the system will enforce the ACID rules. Nothing in the COM+ programming model requires you to think about the two-phase commit protocol.

If you want to read more on the subject, pick up a copy of Principles of Transaction Processing by Bernstein and Newcomer (Morgan Kaufman Publishers, 1997), which explains the low-level details of the two-phase commit protocol that are important to system implementers and administrators (in addition to many other important topics). If you plan to make a living writing OLTP applications, this book is required reading.

The Distributed Transaction Coordinator

Microsoft's TM is the Distributed Transaction Coordinator. This product initially shipped with SQL Server 6.5, but products such as COM+ and Microsoft Message Queuing Services (MSMQ) now use it heavily as well. The DTC runs as a system service on Microsoft Windows 2000 and on Microsoft Windows NT. Figure 8-4 shows how the DTC can act as a coordinating TM and also as a participating TM.

click to view at full size.

Figure 8-4 The DTC is used by products such as COM+, MSMQ, and SQL Server.

The DTC is based on a protocol called OLE Transactions, which defines a set of COM interfaces through which transactional applications and RMs communicate with the DTC. X/Open is another popular standard used by products such as Tuxedo, Encina, and TOP END. X/Open, like OLE Transactions, standardizes the way in which transactional applications and RMs communicate with TMs.

In the early days of MTS, SQL Server and Oracle were the only two RMs that provided interoperability with the DTC. Today, the list of RMs that work with the DTC is fairly long. Some RMs are written to use OLE Transactions. Other, X/Open-based RMs require bridging software to work correctly. For details about interoperability, you should consult the MTS SDK as well as the vendor of your resource manager. From this point on, I'll assume that you have one or more RMs that are interoperable with COM+ and the DTC.

Interacting directly with the DTC

You can execute distributed transactions using the DTC in two ways. The easy way is to use declarative transactions and let the COM+ runtime make all the complicated calls to the DTC for you. The second (and more manly) option is to create an application that communicates with the DTC directly. If you choose this second approach, you'll be writing your code in C++.

I'd like to digress for a second and describe the requirements of writing code directly against the DTC. You'll never actually do this as a Visual Basic programmer, but it's important to walk through the basic steps so that you can appreciate what the COM+ runtime does on your behalf when you run a declarative transaction.

The transactional application must first establish a connection with the DTC by calling DtcGetTransactionManager to obtain an ITransactionDispenser reference to the DTC proxy core object. The ITransactionDispenser interface contains a method named BeginTransaction. When you invoke this method, the DTC creates a new transaction object and returns a reference to your application. This transaction object exposes a Commit method and an Abort method through the ITransaction interface. When you create a transaction, you can specify both the default isolation level and a timeout interval.

Next, you must establish a connection to one or more RMs. For example, you can connect to a DBMS such as SQL Server or Oracle using an OLE DB provider. It's important to understand that the OLE DB provider acts as an RM proxy. After you've connected to a few RMs, you must explicitly enlist these connections by making calls to OLE DB. Once your connections are enlisted, you can execute SQL operations such as SELECT, INSERT, UPDATE, and DELETE. All your reading and writing activity is charged against your distributed transaction.

If the transactional application calls Abort, the coordinating DTC tells all the participants to roll back their changes and release their locks. If the transactional application successfully completes its work on all RMs, it calls Commit to tell the coordinating DTC to start executing the two-phase commit protocol. The coordinating DTC calls all the participants in parallel, and asks them if they're prepared to commit their work. The fact that it makes these calls in parallel means that the local DTC doesn't have to wait for the first participant to respond before sending the prepare request to the second participant. This approach improves performance significantly.

After the coordinating DTC receives an "I'm prepared" response from each enlisted participant, it logs the fact that the transaction was committed and returns a successful response to the transactional application. This is where phase 1 ends and phase 2 begins.

In phase 2, the coordinating DTC sends a "Time to commit" message to all participants in parallel. Each participant commits its changes, releases its locks, and sends an "I'm done" message to the coordinating DTC. Once the coordinating DTC receives all the "I'm done" messages, it can forget about the transaction because there's no longer any need to recover the transaction in case of a system failure.

As you can see, writing a distributed transaction in this manner requires a lot of attention to low-level details. You should also observe that this approach is similar to writing a local transaction in the sense that it's a procedural paradigm. You make explicit calls to begin, commit, and roll back the transaction. Fortunately, COM+ provides a declarative programming model that makes things much easier. However, you should keep in mind that behind the scenes with a COM+ transaction, things happen exactly as they've been described here. COM+ adds value by hiding the gory details of interacting with the DTC and enlisting RMs.



Programming Distributed Applications with COM+ and Microsoft Visual Basic 6.0
Programming Distributed Applications with Com and Microsoft Visual Basic 6.0 (Programming/Visual Basic)
ISBN: 1572319615
EAN: 2147483647
Year: 2000
Pages: 70
Authors: Ted Pattison

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net