Is “fair queuing” possible with JMS

*爱你&永不变心* 提交于 2019-12-05 00:57:25

The first option to consider would be to have a multi-threaded consuming application. Assuming a thread per session/consumer it would be possible to setup either sync or async receive with a selector. Each selector would be keyed to a specific user.

Working with the assumption the JVM werereasonable equitable in terms of dispatch of threads (which I would be happy to assume) AND there weren't any deadlocks in the application code I would assert the requirements would be fullfilled. One thread might get stuck with a users million jobs the rest won't be affected.

If however a single threaded application is desired, then nothing in JMS specification in and itself could help. Their may be vendor extensions of course that could help. However the other option would be a for an application to look at each messages and put it a specific queue for the user id. The final consuming application itself would then 'round-robin' between these queues to get the work. Needs another application but you have a very deterministic system.

I would suggest using message priority for that + setting consumerWindowSize=0 and always have the client to pick a new message from the server.

You would have more latency on the messages but you would always have the messages coming from the server.

Notice that there are races that you will need to consider. what if you are consuming Message C and Message B arrived? you will then consume C for later consume B. But that's not much you could do there since C is under consumption already.

You may also consider Message Grouping but you would be binding a messagegroup to a single consumer from your load balancing.

You are wanting the JMS broker to implement a message delivery algorithm (fair queuing) that is not, as far as I know, part of the JMS specification. It may be possible to find a way to make the broker do this, but I doubt it, and any solution you come up with is likely to be broker-specific.

Instead, why not put the desired queuing algorithm in your own application? For example: write a "fair queuing forwarder (FQF)" application that subscribes to all the messages, in whatever order they come from the broker. Have this FQF application consume messages as fast as possible, so that the JMS broker queue is always empty or near empty. The FQF application could then store the messages in a local queue, and republish them one at a time, in whatever order your desired queuing algorithm determines, to a queue or topic that the ultimate message processing application is subscribed to. On this end you would probably want to use transactions or some sort of flow control so that the FQF application only publishes messages at the rate they can be processed by the end system.

To put this in terms of your example, the messages represent jobs to be processed in a certain order based on a user id attribute in the message header. So I'm suggesting that you write a job scheduling algorithm that passes the jobs to the job processor using whatever queuing algorithm you want.

This way, you would have complete control over the message processing order, without having to somehow "trick" the broker into doing what you want. You would be using JMS simply as a message delivery mechanism, so you don't have to write your own message passing protocol.

Not sure I exactly understand this, but it's problematic that your property has thousands of possible values and that it changes over time. That sounds like a typical 'hash-value to the rescue' problem. So how about creating the hash value of that property and then doing a modulo of that value to derive a fair, but previously known value?

Let's assume it is practical to have 100 consumers processing from 100 queues, named Q0 to Q99. Then you could do this in your JMS producers:

String queueName = "Q" + user.hashCode()%100;

And this is the queue name that producers send to. Also the user value is added as property. The same user will go to the same queue (and queue up, if there are too many), and users are almost fairly distributed across consuming applications.

Now you still have the problem of one bad user creating a million jobs. A second part of this solution could be a JMS selector that is empty on startup. Once the first message is consumed, you count then number of jobs for each user and once you reach a threshold, e.g. 10 jobs from the same user, you temporarily disallow this user by adding a selector such as: 'user NOT LIKE user123'. If there is more than once such user, you accumulate the selection with 'AND'. Once the consumer doesn't get any further messages, you set this consumer's select to be empty and start processing the queue again.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!