October 20, 2014
How to Use Unit of Order with OSB
Using Unit-of-Order with OSB. Download the test project.
Unit-of-Order (UOO) is an Oracle (BEA) extension to standard JMS.
It enforces the order of messages with the same key so that the messages are consumed in the order they were added to the queue.
This functionality works in a cluster, too, by assigning each UOO key to one and only one managed server.
When Ordered Updates Are Needed
Suppose I update my phone number on a site. The update message is placed into a JMS queue to process it asynchronously. Meanwhile, I change my mind and update my phone number once again - now to my cell phone number. Yet another message is placed into the queue.
In an ideal world the first message would be processed first, and the second, well, last, so my account finally contains my cell phone number.
In the real world, though, the first message may be delivered to a slow server, get delayed, and be processed after the second message. My account then will contain the outdated information.
How Unit-of-Order Helps
Unit-of-Order lets you create one or more logical message sequences, each of which is consumed in a first-in-first-out manner.
In the example above, my phone number updates may be assigned a UOO key that is unique to me. Most likely, it is my account number (e.g. 12345). Then all messages that have my account as a key will be processed in the order they were placed into the queue:
12345:[ 1st:Update(416-222-3456), 2nd:Update(416-222-3333) ]
Any consumer that reads the queue will not see the second message until the consumption of the first message has been acknowledged.
The Queue Is Not Blocked
An important note: UOO does not block the whole queue while a message is being processed. Messages with different UOO keys are processed in parallel.
The first messages belonging to other accounts (other UOOs) will be visible and consumable even though the first message in my account’s UOO has not been acknowledged yet.
Think of UOOs as virtual parallel queues inside a JMS queue.
The UOO key for a message is kept in a JMS header named JMS_BEA_UnitOfOrder.
Here is an example of a message with the UOO set. The value of the UOO is 12345 (a test account number):
What Do You Need to Do to Use UOO in OSB?
In fact, the only required step is to add the header to the message when you put it into a JMS queue, like this:
A Transaction is NOT required
You do not need to use XA and require a transaction in the JMS-reading proxy.
A transaction is useful for reliable messaging, but ordering in UOO works without transactions, too. Even if some messages get lost due to faults, they get lost in a strict order :-).
Connection Factory Configuration is NOT required
You do not need to set the UOO properties in the connection factory. Those properties are for when we cannot provide the UOO value programmatically:
UOO Playground Project for OSB
I have created a project to test the behaviour of UOO in OSB. You can download it here (sub-project UOO).
The project works with messages produced by a SOAP UI project, and their sequence-number field is generated as the current timestamp (System.currentTimeMillis()). The messages look like this:
<update> <account>12345</account> <sequence-number>1412742171727</sequence-number> </update>
The sleep call in the delaying proxy is up to a few seconds long and random, so messages sent one after another have a significant chance of arriving at the validating proxy not in the same order as they were sent. If this happens, the validating proxy rejects them and reports it when we call it for stats.
We can change various parameters for the entry proxy, connection factory and the JMS queue and observe how they affect the delivery order.
The code, from a 10,000ft view, does the following:
The entry proxy:
Accepts an XML message over HTTP.
Reads the account number into the $account variable.
Puts $account into the JMS header JMS_BEA_UnitOfOrder.
Places the message into a JMS queue.
The delaying proxy:
Reads message from the JMS queue.
Introduces a random delay to simulate unbalanced consumers.
Delivers the message to the validating proxy via HTTP.
The validating proxy:
Remembers the sequence number of the last message in every account to detect any out-of-order deliveries.
Provides the out-of-order statistics on demand.
Let’s look at the logic in a few important UOO-related cases.
The following scenarios are in SoapUI project UnitOfOrder-soapui-project.xml, which is included in the distribution.
JMS Module for Testing UOO
A dedicated JMS module should be configured for the test project:
(Don’t forget to restart the server after the configuration is complete, even if the success message tells you that you don’t have to.)
Baseline: Messages with the Same Account but No UOO
When the UOO is not enabled, and the queue contains a few messages, those messages are processed in parallel.
Our project has a special entry point /Examples/NoUnitOfOrder which places messages in the queue without setting UOO. I sent, one after another, 12 messages belonging to the same account 12345 to that endpoint.
When I then called the validation endpoint /Examples/UnitOfOrderValidator, the response shows a high number of messages that arrived out of order – 6 out of 12:
<error-count-response> <account>12345</account> <stats> <total>12</total> <errors>6</errors> <cross-account-ooo>0</cross-account-ooo> </stats> </error-count-response>
As you can see, the default JMS queue doesn’t maintain the message order.
Same Account with UOO
When UOO is enabled, the picture is radically different. Only when the leading message has been removed from the queue, will the next message be consumed.
I sent 12 messages via an entry point /Examples/UnitOfOrder which sets the UOO key for the messages. The account number in this test is 789000.
The validation proxy detected no out-of-order executions:
<error-count-response> <account>789000</account> <stats> <total>12</total> <errors>0</errors> <cross-account-ooo>0</cross-account-ooo> </stats> </error-count-response>
Also, if you run this test, you may notice that it takes longer to complete. This is understandable, because every message is executed in sequence rather than in parallel as in the non-UOO case.
UOO with Transactions
While not tested in this project, it is important to note how UOO works in the presence of a transaction.
Just like without a transaction, the next message within the same UOO is not delivered until processing of the leading message has been completed.
When, however, the transaction fails and is rolled back, the leading message is placed back into the queue. All the following messages are blocked until the leading message is retried and succeeds.
If the leading message expires or is retried too many times and deleted or moved into an error queue, the following messages are unblocked and processed.
Different Accounts with UOO
Let’s confirm that different UOO keys do not block each other. Let’s place into the queue 12 messages for one account (with one UOO key) and 12 messages for another (with another UOO key).
We expect the messages within the same UOO to maintain their order. But messages within one UOO may be delivered faster than messages with lower sequence numbers in another UOO.
And this is exactly what happens:
<error-count-response> <account>77777</account> <stats> <total>30</total> <errors>0</errors> <cross-account-ooo>22</cross-account-ooo> </stats> </error-count-response> <error-count-response> <account>88888</account> <stats> <total>29</total> <errors>0</errors> <cross-account-ooo>2</cross-account-ooo> </stats> </error-count-response>
Messages from account 77777 maintain the strict order among themselves, but cut in front of messages from account 88888 22 times. Messages from account 88888 did the same twice.
(The difference is because messages for account 77777 were delivered to the entry proxy first, so they had a handicap.)
Unit-of-Order in a Cluster
The tests above were performed on a single node.
But how does UOO work in a cluster?
How do different cluster nodes order the messages belonging to the same UOO key?
What happens when the connectivity between the nodes fails?
The designers of the UOO functionality made a simple and clever decision - each UOO key is handled only by a single cluster node.
When a message is placed into a distributed queue, its UOO key is used to calculate a hash. That hash is then used to select one of the managed servers. The message is immediately placed into that managed server’s store.
For instance, I have a two-node cluster. In my test, messages with keys 12345 and 56789 are sent to managed server 2. But the messages for a slightly different key, 12346, are sent to managed server 1:
Since the messages with the same UOO never end up on different nodes in the cluster, the scenarios we tested above in a single-node domain remain true in a clustered environment, too.
When a Server is down
What if the computed hash points to a server that is currently down or not accessible?
Weblogic cannot place the messages for it into any other managed server, because that may cause an out-of-order execution - there could be earlier messages waiting in the stopped server queue.
The only reasonable thing to do is to reject the new messages, and this is what Weblogic does:
<con:fault xmlns:con="http://www.bea.com/wli/sb/context"> <con:errorcode>BEA-380002</con:errorcode> <con:reason> hashed member of UOO!TestUnitOfOrder is UOO!UOO2@TestUnitOfOrder which is not available </con:reason> ... </con:fault>
Hence be careful: UOO guarantees order but may cause denial of service (for some accounts).
I'm building SOA enterprise systems for clients large and small for almost 20 years. Most of that time I've been working with BEA (later Oracle) Weblogic platform, including OSB and other SOA systems.
Feel free to contact me if you have a SOA project to design and implement. See my profile on LinkedIn.
I live in Toronto, Ontario, Canada. Email me at firstname.lastname@example.org