Java CAPS Tip : Reading MSMQ Messages with high TPS
By The Old Toxophilist on Nov 24, 2008
Although this code has been implemented within Java CAPS 5.1.3 it is perfectly valid to run the same functionality within a Java CAPS 6 environment and hence the project can simply be imported into either.
When using the MSMQ eWay it can be configured in a number of ways to allow either a "Peek" or a "Get" to be performed. For experience it appears that executing the "Get" immediately reads and commits the read from the MSMQ and hence if you connect the MSMQ eWay to an MSMQ Queue with a receive this will read and commit the record regardless of whether the message can be written to the destination queue. This appears to be a feature of the MSMQ Queuing implementation and we could potentially work around this using a "Peek" connection first and then a "Get" but this has the problem that we can only poll the MSMQ Queue every 100 ms (minimum) and hence read a maximum of 10 TPS.
A simple solution to this would be to have a scheduled JCD that runs every 1 second and reads X (250) messages and writes them to the STCMS Queue. This appear to be a good implementation until we take XA into account. At this point if the JCD can not write to the STCMS the JCD will keep executing every second reading X (250) messages and committing them without being able to write them to the destination Queue. Hence to resolve this issue I have built and tested the following example that will only read the MSMQ Messages when the destination STCMS is available.
So if with consider that our requirement is to read from the MSMQ and write to a remote STCMS running on Solaris, AIX, etc. Because the MSMQ eWay requires a number of windows dlls this portion of the application must run on a windows machine but given the flexibility available for deploying Java CAPS application this is not a problem.
Connectivity Map (Process)
The steps within the process are best illustrated using the Connectivity Map below. It can be seen from this that the processes essentially consists of two steps.
- Scheduled JCD that writes X messages to a triggering Queue.
- JMS Trigger JCD that reads and sends a MSMQ Message.
The Scheduled JCD is triggered every second and will write a configurable number of messages to the qTrigger Queue these messages in turn will trigger an instance of the Read and Send JCD that will read a message from the MSMQ and write it to the qReceiveMSMQ Queue. The Read and Send JCD is connected to the qTrigger using the Connection Consumer mode and configured to initiate an appropriate number of threads (100).
It can be seen from the code above that the jcdSchedule simply sends a simple, meaningless, message to the qTrigger Queue X number of time where X is defined by the system property msmq.read.batch.size which can be set by adding the following to the domain.xml file.
In addition to this we set the time to live for the message to 2 seconds because we expect them to only exist on the queue for 1 second before being read and triggering the read from MSMQ. This also reduces the excessive build up of messages if we do not match the batch size used by the scheduler to the size within the Connection Consumer mode configuration.
The jcdReadAndSendMSMQ simply reads a MSMQ Message and sends the contents to the STCMS Queue or if there are no MSMQ Message committing the qTrigger message and sending out a message.
The Deployment of the components is key to how this project works. It can be seen from the image below that the qTrigger and the qReceiveMSMQ are deployed on the same Queue Manager and this is what allows us to control the initiation of the MSMQ read to only occur when the destination queue, qReceiveMSMQ, is available. In the actual scenario, on the customers site, the Integration Server was installed on Windows whilst the STCMS was installed on AIX which allowed messages to build up on the MSMQ if the AIX STCMS was not available and when it became available the messages would be transferred from MSMQ to STCMS thus allowing the further processing to occur.
Configuring The Logicalhost
Before you can execute the attached project you will need to configure the Logicalhost so that it can access the MSMQ environment. This is done by downloading the MSMQ eWay runtime components from the Repository and installing them in a Widows directory. Once this has been done the msmqjni.jar must becopied to the <Domain>\\lib\\ext directory and the Native Path Prefix for the Domain should be modified as follows (assuming you have extracted the runtime dlls to C:\\JavaCAPS6\\msmqruntimejni).
Configuring MSMQ XA and MSDTC
To my peril I found out how hard it is to actually get MSMQ XA transactions running the information, although it is on internet, can be difficult to find. So I have decided to briefly document it here. Before using the XA functionality and MSMQ you will need to make sure the MS Distributed Transaction Coordinator (MSDTC) is running and that XA is specifically enabled.
- Check the Windows Service Distributed
Transaction Coordinator is set to Automatic and Started.
- Select Control Panel -> Administrative Tools -> Component
- Expand Console Root -> Component Services -> Computers and
select Properties on My Computer.
- In the properties select the MSDTC Tab and select the "Security
- Within the Security Configuration Dialog check the "Enable XA Transaction" and press OK. Acknowledge the pop up and select OK again on the Properties Dialog.
- At this point you will need to restart your MSMQ Service
(personally I restarted the PC) to make sure it picks up the changes.
Following a restart if you check the MSDTC Startup Event log entry it
will look like the following:
MS DTC started with the following settings:
Security Configuration (OFF = 0 and ON = 1):
Network Administration of Transactions = 0,
Network Clients = 0,
Inbound Distributed Transactions using Native MSDTC Protocol = 0,
Outbound Distributed Transactions using Native MSDTC Protocol = 0,
Transaction Internet Protocol (TIP) = 0,
XA Transactions = 1
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
The key piece of information is that the XA Transactions = 1 and this indicates that XA Transactions are available.
When you application is running you can now see within the Component Services / Distributed Transactions / Transactional Services that the statistics are changing.