How to Improve Your Java/JMS MQ Tuning Cred.

Here’s my version of a cheap Info-Commercial:

  • Do you want to impress your colleagues?
  • Do you want to impress your boss, so that you can receive a big fat bonus?
  • Call today and we’ll show you how to impress the MQAdmins in your company!
  • And if you call within the next 5 minutes, we’ll even double that offer by throwing in ‘how to reduce your CPU usage on both the client and MQ servers’!

If you don’t know what I talking about, please go read the following to blog posting:

I’m going to try and make this blog posting from 10,000′ view with lots of pictures to drive home the point that with a simple configuration change you can:

  • reduce the number of failed MQGet API calls
  • which in turn will make your applications faster
  • that lowers the CPU consumption of client server
  • and lowers the CPU consumption of MQ server.

So much benefit for such a simple change!!

Why IBM has not documented the JVM environment variable ‘com.ibm.mq.jmqi.defaultMaxMsgSize’ is beyond me. This should be front and center whenever IBM talks about tuning JMS and Java (non-JMS) applications but it is not. I have been doing Java programming since the 90’s and Java MQ programming since SupportPac MA88 became available (which was a long time ago!). In all of that time, I have never heard about this JVM environment variable. Hence, I’m will to bet there are tens of thousands of Java applications and hundreds of thousands (probably millions) of JMS servers running and all performing excessive number of MQGets API calls all because nobody ever told them about it.

For all test scenarios, I used the same 100 non-persistent MQRF2 (aka JMS) messages:

  • The first 25 messages are random sized messages between 735 bytes and 200KB
  • The next 25 messages are 8439 bytes in size
  • The next 24 messages are 735 bytes in size
  • The next 15 messages are 8439 bytes in size
  • The next 11 messages are 12298 bytes in size

The message distribution looked like:

I am getting questions about JVM memory usage. So, I ran both MQTest12L.java and MQTestJMS12L.java in bindings mode and client mode using different values for com.ibm.mq.jmqi.defaultMaxMsgSize.

For each of the following 4 pictures of JVM memory usage, the horizontal axis is made up of 106 points:

  • 1st is memory usage at the beginning of the main() method
  • 2nd is memory usage after MQCONN API call
  • 3rd is memory usage after MQOPEN API call
  • 4th to 103rd are memory usage after each MQGET API call (100 calls)
  • 104th is memory usage after MQCLOSE API call
  • 105th is memory usage after MQDISC API call
  • 106th is memory usage at the end of the main() method

The vertical axis is the JVM memory usage in bytes.

Here is a picture of MQTestJMS12L.java connecting in bindings mode using different values for com.ibm.mq.jmqi.defaultMaxMsgSize.


Here is a picture of MQTestJMS12L.java connecting in client mode using different values for com.ibm.mq.jmqi.defaultMaxMsgSize.


Here is a picture of MQTest12L.java connecting in bindings mode using different values for com.ibm.mq.jmqi.defaultMaxMsgSize.


Here is a picture of MQTest12L.java connecting in client mode using different values for com.ibm.mq.jmqi.defaultMaxMsgSize.


I have no idea why JMS (bindings & client modes) MQ components uses less memory and is a better memory manager than the non-JMS MQ components. You would think it is the same internal JMQI component. Also, the other weird item from the 4 charts is why is using a value of 4MB for com.ibm.mq.jmqi.defaultMaxMsgSize causing the JVM to use an extra 25-30MB of memory. Clearly, there is some sloppy programming going on inside the internal JMQI routine.

The 100 test messages that I am using are sized between 735 bytes and 200KB (see above). So clearly, the ‘best bang for my buck’, is to set com.ibm.mq.jmqi.defaultMaxMsgSize to a value above 200KB. (i.e. 262144 – 256KB). Hence, there will be zero MQGet exceptions with a Reason Code of 2080 (MQRC_TRUNCATED_MSG_FAILED) and there will NOT be any noticeable difference in JVM memory usage.

If you know the range of sizes of your messages then I would pick a value for com.ibm.mq.jmqi.defaultMaxMsgSize that is larger than the largest message size unless that value is above 1MB. Above 1MB, it appears to be a trade-off between higher JVM memory usage and reducing the number of MQGet exceptions with a Reason Code of 2080 (MQRC_TRUNCATED_MSG_FAILED).

The bottom line is that doing something, anything is far, far better than doing nothing at all!!! The title says ‘How to Improve Your Java/JMS MQ Tuning Cred.’, well, pick and set a number whether that is the largest message size or the average message size or the median average message size or throw a dart at a dart-board. Pick a reasonable value and set the JVM’s com.ibm.mq.jmqi.defaultMaxMsgSize environment variable to it. You never know, you may even get a bonus or a promotion because of the awesome change you made! 🙂

Update: Currently, the JVM environment variable ‘com.ibm.mq.jmqi.defaultMaxMsgSize’ is undocumented. Hence, the usage may change in a future release.

Regards,
Roger Lacroix
Capitalware Inc.

This entry was posted in IBM i (OS/400), IBM MQ, Java, JMS, Linux, macOS (Mac OS X), Programming, Unix, Windows, z/OS.

Comments are closed.