Reputation: 1817
I have a question regarding workable design patterns for ActiveMQ. I have a single-threaded database client based on ActiveMQ - callers create a temporary response queue, JMS "send" a SQL query to the correct queue, and wait for a response on the temporary queue. Problem is, complex queries that run slowly mean that the single-threaded consumer bogs down...if a query takes five minutes, no other queries against that database can occur till the first one completes. The queries themselves are atomic and we don't use any manner of transaction processing at the JMS level. The solution I'm considering is to multi-thread the consumer, but I want to be sure I'm not going to run afoul of any ActiveMQ or JMS restrictions.
I understand I can just switch from queues to topics, and then I can run what I have today across many threads. It might come to this, but for now, the queue structures constitute an "API" that gets used in a lot of ways, so it's not easily changed to something topic-based.
Instead, I envision a main thread that acts just like the current consumer in terms of fetching messages from the bus, except instead of processing the messages inline (as we do now), the message would be queued to a separate thread. The child thread would do the database work, then send the results back to the original requestor on his temporary queue.
If I understand the spec correctly, I could use a single "connection" shared across threads. There would only be a single consumer, so it would just continue to be in a message receive loop, just like today. In the new child threads, we'd start a separate JMS session on the existing connection (sessions can't be shared), wait for work, process the queries, and finally send any results to the requestor's temporary queue so that he gets his output. I don't think we need massive parallelism, so I'm thinking just to have a handful of child threads preallocated and waiting for work.
Here are the questions:
Upvotes: 0
Views: 1433
Reputation: 4316
This sounds like a worker model and queues are a good choice for that. Topics would be good if you wanted the same query request to be processed by multiple systems.
Yes. The only limitation on a temporary queue is that it goes away once there is no longer a message or a producer-or-consumer attached. An alternative approach is to use real queues and use ActiveMQ's garbage collection 'gc' to automatically clean them up. The advantage here, is that you have more readily available visibility to the queues in use and if there are any stragglers.
Sessions can be shared across producer and consumer. The JMS object hierarchy is similar to the JDBC one. You have child objects off of each other. At low load and number of connections (say, less than 8 connections per CPU core) there is no real harm in having dedicated Connection-Session-Consumer objects for each thread-- esp if you turn on pooling. It makes error handling and rollback easier.
Latency and/or network I/O. If you are doing less than 512 messages per second where message size is 4k or less, one connection isn't a problem.
Depends on total # of connections and messages-per-minute and message size.
Error handling. If you do JMS local transactions (recommended!) your error handling is at the session level for rollback.
Nope, you are good! Multi-threaded consumer is the first go-to approach for working around a slow consumer pattern.
Recommendations--
The connection pool prevents the broker from connection thrashing. This pattern is the most reliable for error handling and avoiding leaked resources which leads to messages loss.
Upvotes: 1