Thursday, July 5, 2007

Performance of the JRuby JMS messaging solution

Please note: This performance testing method was flawed as it was undertaken in the 'development' environment. There are more accurate results here.

Now that we have a JRuby JMS implementation, how does it perform? I did a quick test to compare the ActiveMessaging solution with the JRuby JMS messaging solution. The Customer application, Orders application, ActiveMQ server and the message handler (ActiveMessaging poller/JRuby JMS process) were all running on my laptop. As such, the absolute timings presented here are not relevant, but the comparison between the two solutions is relevant, and somewhat interesting.

Testing Method


I sent 100 messages from the Customer application and measured the elapsed time between when the message was sent, and when processing had finished in the Orders application. With each solution, I captured the current time immediately before the message was sent in the Customer application, and captured the current time immediately after it was processed in the Orders application. These were the results:



As you can see, the elapsed time increases at a constant rate for the ActiveMessaging solution, as the 100 messages pile up in the queue. The last message took just under 14 seconds to be processed (with a significant amount of that time being spent in the queue). Contrast this with the Java JMS solution, where the 100th message took only 2.5 seconds to be processed. Even more interesting than the difference between the two times is the flattening of the Java JMS curve. The elapsed time does start to grow as the messages pile up in the queue, but after around the 60th message, the elapsed time remains relatively constant. This represents a great advantage when trying to ensure predictable performance of your messaging solution.

Conclusion


We are going to look seriously at using JRuby and JMS on our current project in place of ActiveMessaging. I mentioned in my last post that although I deployed the Orders application using JRuby, you can actually leave the web-app itself in MRI (Matz Ruby Implementation) and just deploy the message handler in JRuby. The message handler is running as a separate process to the web application. It needs to load the rails application to have access to the Customer model so that it can save the message contents to the database, but that's it. The web requests can still be handled by an MRI-deployed rails app. So that's probably what we will end up doing. Thoughtworks Studios recently released a project management tool called Mingle that is deployed on JRuby, so it's definitely possible to deploy the whole web-app in JRuby, but as an interim step we will probably stick with MRI.

4 comments:

tirsen said...

That's a very interesting benchmark!

My theory is that the JMS solution achieves much higher throughput by utilizing multiple threads, where as a13g has been specifically designed to prevent multiple threads in Rails. It's really interesting that Rails doesn't fall over when getting exposed to multiple threads.

Have you measured how many connections gets opened up to the database? I think this solution could benefit from connection pooling.

It would be interesting to integrate this approach into a13g so you could benefit from the higher throughput and still be able to use a higher level programming model.

kookster said...

That is some interesting stuff - but I am with Jon, the linear graph for the poller is consistent with serial processing of each message, whereas if it was processing with multiple threads, you would get a flattened curve like the jms curve.

Are you using the jruby jms adapter in active messaging, or stomp?

Ola contrbuted a grest jruby only adapter which needs no poller -

http://groups.google.com/group/activemessaging-discuss/browse_thread/thread/d3cfc1a4c25f3ce7

This was the basis of the jms adapter now in activemessaging, I think all it is missing is that the one in activemessaging does use a jruby specific poller, and the jndi lookup stuff - more info about it here:

http://groups.google.com/group/activemessaging-discuss/browse_thread/thread/f040badd01d6cbee/bb272bd28db7967a

cool stuff, I'm gonna have to watch your blog more closely.

-Andrew Kuklewicz

Cliff Moon said...

I think that a more instructive benchmark would be to start as many poller instances as there are Java threads. As Jon and Andrew said, activemessaging is architected to avoid threading issues with rails.

The good news is that I'm still massaging the JMS adapter in ActiveMessaging and my goal is to make it run in a number of different scenarios. Feel free to browse the a13g discussion group, I'll be posting some of my thoughts on the JMS adapter there shortly. Thanks.

Shane Harvie said...

I've finally gotten around to testing the JMS implementation again. With only 100 messages, only one thread opens up. (I just did puts "Thread id: #{Thread.current.id}" within the onMessage method, and only saw one thread. So I think the testing method, whilst not perfect (because of all of the puts statements) is ok. I think jruby JMS is much faster.