开发者

MQ Series Messages get read more than once

开发者 https://www.devze.com 2023-02-11 01:49 出处:网络
I\'ve a problem whereby a message occasionally gets read from the Q more than once. I\'m using .NET wrapper for MQSeries (amqmdnet.dll) and read messages, using Win Service.

I've a problem whereby a message occasionally gets read from the Q more than once. I'm using .NET wrapper for MQSeries (amqmdnet.dll) and read messages, using Win Service.

Here's how I do it with VB.NET:

'QManager
 Dim properties As Hashtable = New Hashtable(4)

        properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_CLIENT)
        properties.Add(MQC.CHANNEL_PROPERTY, channelName)
        properties.Add(MQC.HOST_NAME_PROPERTY, iPAddress)
        properties.Add(MQC.PORT_PROPERTY, 开发者_JS百科port)

        QManager = New MQQueueManager(queueManagerName, _
                                              properties)


'Q itself
getMessageOptions.Options = _
            MQC.MQGMO_FAIL_IF_QUIESCING Or _
            MQC.MQGMO_WAIT Or _
            MQC.MQGMO_SYNCPOINT

getMessageOptions.WaitInterval = 1000 ' read from config

Dim locker As New Object

System.Threading.Monitor.Enter(locker)

Q.Get(message, getMessageOptions)

QManager.Commit()

System.Threading.Monitor.Exit(locker)

I heard that Q.Get(message, getMessageOptions) makes the message unavailable for other readers, QManager.Commit in turn just removes the message from the Q (by analogy with .NET Peek & Dequeue). That on its own should eliminate need for Monitor.

In my Win Service multiple threads read the Q and we suspect that due to a low polling interval (100ms and less) the wrapper doesn't get enough time to update 'Read' flag of the message, so it get's picked up more than once by overlapping threads. Historically the same message gets read up to four times.

Before increasing the polling interval, I wanted to make sure if I'm doing things the right way. Could anyone suggest on any problmes with my approach?

Thanks.


Let's address a number of points from the post and subsequent comments:

  1. Performing a GET in WMQ does indeed make the message unavailable to other readers. A GET outside of syncpoint permanently dequeues the message immediately whereas a GET under syncpoint makes the message unavailable to other readers unless a BACKOUT occurs. A BROWSE operation however provides no such protection.
  2. The queue manager mediates access to the messages. There is no direct manipulation by the MQ application of the queue or message internals, and thus no opportunity for the .Net wrapper to manipulate a "Read flag".
  3. The wait interval is how long the outstanding GET blocks the program if the queue has no available messages and with a value of 1000 that interval is one second. If there are many messages on the queue and the program loops immediately, the effective polling interval is however long it takes the program to process the message. The wait interval has no affect on throughput dequeueing messages from a deep queue since the queue manager never has to wait for a message to arrive.
  4. WMQ offers a number of different levels of reliability. These are controlled by things such as message persistence, acknowledge mode and transactionality. For example, a non-persistent message retrieved outside of a unit of work provides at-most-once reliability.

With regard to threading and synchronization, the WebSphere MQ: Using .Net manual has this to say:

The implementation of WebSphere® MQ .NET ensures that, for a given connection (MQQueueManager object instance), all access to the target WebSphere MQ queue manager is synchronized. The default behaviour is that a thread that wants to issue a call to a queue manager is blocked until all other calls in progress for that connection are complete. If you require simultaneous access to the same queue manager from multiple threads within your program, create a new MQQueueManager object for each thread that requires concurrent access. (This is equivalent to issuing a separate MQCONN call for each thread.)

If the default connection options are overridden by MQC.MQCNO_HANDLE_SHARE_NONE or MQC.MQCNO_SHARE_NO_BLOCK then the queue manager is no longer synchronized.

So the synchronization is done for you but the exact behavior depends on whether each thread has its own connection. This is because transactions are connection-scoped. If one connection serves many threads and one of the threads calls COMMIT then all threads under that connection are in the same unit of work and all COMMIT at once.

There are a couple of possibilities that can result in duplicate messages other than browsing them. All of these are variations on messages being backed out. Backouts may not always be under program control. When many transactions are under syncpoint simultaneously, several tuning limits come into play including MAXUMSGS, log file primary and secondary extents and several others. If any of these limits are exceeded, the QMgr will cancel the oldest outstanding unit of work to make room for the next one. Another reason backouts occur is if the client connection is interrupted. In this case any GETS under syncpoint are rolled back and the messages become available again.

One way to determine whether this is happening is to inspect the backout count of the messages as they are read. A robust messaging application will routinely check this value as part of poison message handling and requeue (or delete and log) messages where the backout count exceeds some arbitrary threshold. This prevents an unreadable message from permanently locking a thread. When duplicate messages are seen it might be helpful to log any messages where the backout count exceeds zero rather than simply requeueing those that exceed the threshold.

Another way to see exactly what is happening is to use the tracing facilities of WMQ or SupportPac MA0W. Either of these will show exactly what API calls are being performed, by which applications and threads, and with which options. If your trace shows that duplicate messages are being delivered to non-browse GET calls without BACKOUT occurring, then it is a defect for which you can request a fix.

There is a slight chance if you are using older .Net code that the problem is a defect that has been fixed. I did not see any defects in the fix lists that would result in duplicate messages but if your .Net client is not at a recent v7 you should be considering upgrading soon anyway. The v7 classes are much more functional, and in fact are now fully integrated into WMQ and supported. There is also the small matter of WMQ v6 going end-of-support as of September 2011. You can get the latest WMQ client in SupportPac MQC7. If you have already installed a v7 client and need to upgrade to v7.0.1.4 you can install the latest client over the older v7 one or apply the latest Fix Pack (FP 7.0.1.4 as of this writing) from the Recommended Fixes page. The Fix Pack upgrades client as well as server installations.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号