OK, now that you promised that you won’t store your messages in the broker (see part one of this post series), let’s consider one more thing that you should avoid when dealing with messaging systems.
One thing that reoccur regularly is folks (knowingly or unknowingly) creating and tearing connections to the broker for every message they produce and consume.
This anti-pattern is especially common in two environments: Stomp and Spring. Stomp is very lightweight text-oriented messaging protocol. Which makes it really easy to write clients in almost any programming language available. This is one of the main strengths of Stomp and if you’re not JVM-exclusive shop I strongly recommend you to take a detailed look at it. But this impose a problem of course; large number of clients are poorly written and/or used inappropriately. For example, you can have a script which when ran will send or consume some messages from the broker. So if you don’t care much, you’ll open a new connection every time, send and consume messages and (hopefully) disconnect from the broker. Then you’ll put your script under load which will then transfer that load to the broker.
Spring, on the other hand, uses nice abstractions for dealing with JMS brokers, but the problem is that it was designed to be ran in a container of some kind and it is expected that container will manage resources for it. So when you write your standalone Java application and don’t care about this you end up with messaging clients behaving badly. A new connection, session, producer, consumer objects will be created for every message exchange and that far from optimal.
Why is all this such a problem? Well, first of all opening and closing connections requires from broker to do some work and having large number of clients opening and closing connections to exchange a single message produces a huge overhead and steals resources broker could use to do some other useful work. This is not specific to messaging and broker. You don’t open and close a database connection for every query (hopefully) for the same reasons. And also a spike in load in this case can spike in number of sockets used (as they need some time shutdown on the system) and eventual system resources exhaustion.
Besides this, messaging services are all about long lasting connections and clients. ActiveMQ implements various concepts, like producer flow control and consumer message prefetch, which are aimed to improve messaging experience and performance of the whole system. Not only that these messaging mechanisms are meaningless in a short-lived connections scenario, but can also introduce additional overhead in the system.
Finally if you have network brokers, information on large number of message consumers coming and going will be propagated through the network. This can significantly increase a broker to broker traffic and even impact the stability of remote brokers.
So what’s to be done? In Spring it’s easy, just use some kind of a cached connection factory and you’ll be sorted. There’ll be no more a new connection, session, producer, consumer for every message exchanged. More resources on ActiveMQ Spring support can be found here so please give it read if you’re using JMS Spring clients in your applications.
For Stomp, there’s no silver bullet. But for starters be aware of what you’re doing and try to reuse your resources smartly. If you do it, messages will flow smoothly and you’ll have a stable system.
Nicely said Dejan. Can you comment on available techniques for connection management in a karaf and blueprint container?
Thanks John. Karaf and blueprint doesn’t do anything regarding connection management, so it’s all on your application. If you’re using Camel or Spring JMS connection pooling is a must.
Very important anti-pattern Dejan!
I just like to add that for the Spring case it is highly recommended to use the CACHE_CONSUMER cache level when consuming JMS messages in Spring in order to achieve best performance.
ActiveMQ provides a PooledConnectionFactory which pools connections, sessions and producers but no consumers (for good reasons).
To avoid creating a new consumer with every msg (which is a sync call to the broker) it is recommended to cache the consumer at Springs DefaultMessageListenerContainer (DMLC).
This also applies to Camel JMS consumers, which uses Springs DMLC underneath.
Thanks Torsten. Perhaps this deserves a post of its own 🙂
That post already exists:
Comments are closed.