JRuby Performance
Asked Answered
N

3

21

I have a Rails 3.2.2 application that I am looking to run using JRuby 1.6.7 (1.9.2 mode).

I have a sample app running in MRI ruby 1.9.3 and a typical request is returning in ~40ms: Completed 200 OK in 36ms (Views: 27.5ms | ActiveRecord: 8.2ms)

Under JRuby using the same request is anywhere from 3 to 20 times slower depending on the page. For the same operation as above it takes ~180ms: Completed 200 OK in 180ms (Views: 153.0ms | ActiveRecord: 24.0ms)

Is this a normal performance difference? I have read that JRuby is roughly equal on speed with MRI. The results hold on my Mac and a Windows server (where unfortunately it will need to run). Packaging it up with Warbler running under Tomcat is just as slow.

The above times are from a basic rails app created for testing the JRuby. On the more complex app the times are even farther apart. On that app there is more ruby code being run on some pages. It seems that the more the page is ruby dependent the greater the performance difference I am observing. I have done no tuning of JRuby, since I don't know quite where to start.

So my questions are: is this normal? What can I do to tune JRuby?

Nydianye answered 20/4, 2012 at 19:21 Comment(0)
S
19
Is this a normal performance difference?
I have read that JRuby is roughly equal on speed with MRI.

No, that's not normal. Once the JVM has warmed up, Rails requests under JRuby are usually significantly more performant than under MRI, both in terms of raw execution speed and garbage collection.

It sounds like your app is misconfigured. The first thing to check is the configuration of Rails itself - please ensure that Rails is not in development mode, and that config.threadsafe! is enabled in your production environment. Threadsafe mode will result in there being only one shared copy of Rails loaded into memory when your app is running.

Also check that your database configuration is taking advantage of connection pooling, e.g. pool: 20 in database.yml.

Finally, check your JVM and JRuby settings – both are highly tunable. You need to ensure that there is enough memory allocated to the JVM upon startup, and then enough memory for normal smooth operation of your application; otherwise the JVM will constantly be forced to prematurely and frequently garbage collect, which will significantly degrade performance.

For example some of the settings for a modestly specced VPS might be something like:

-Xmx500m -Xss1024k -Djruby.memory.max=500m -Djruby.stack.max=1024k

... but don't copy these settings blindly! You will have to experiment and work out what is good for you with respect to the memory resources that are available on your server.

That said, whilst JRuby will probably consume less memory than the total sum of multiple Rails processes under MRI, you will definitely need to allocate a little more up front for a single JVM process. Be generous to JRuby, and JRuby will reward you for your kindness :-)

You can read more about tuning JRuby and the JVM here: https://github.com/jruby/jruby/wiki/PerformanceTuning

Update

You do not need to set config.threadsafe! in Rails 4.0 and above; it is threadsafe by default.

Swirly answered 23/4, 2012 at 16:9 Comment(1)
Running in production mode, compared to the development mode brings sometimes 5-6 times faster response. At least that was in my case. Thanks for noting that.Fingertip
H
4

I'm seeing the same behaviour, but do keep in mind that JRuby needs significantly longer to warm up. I'm actually slightly optimistic that JRuby will eventually catch-up.

It's possible to make this 'warming up' faster by setting a few options. The Ruby -> Java Bytecode compiler can be taught to JIT compile every method on the first invocation by setting the following env var:

export JRUBY_OPTS="-J-Djruby.jit.threshold=1 -J-Djruby.jit.max=16384"

For me, after refreshing a Rails page a few times, it's still 2-3x slower than the MRI Ruby, but at least 3x faster than before.

Also keep in mind that the java runtime is JIT compiling the java bytecode to machine code in a similar manner, but this JIT won't kick in until a method is invoked 10.000x when using the server runtime. This can be configured as well.

export JRUBY_OPTS="-J-Djruby.jit.threshold=10 -J-Djruby.jit.max=16384 -J-XX:CompileThreshold=10" -J-XX:ReservedCodeCacheSize=128M"

With these options, JRuby on Rails gives about the same or better performance than MRI.

Please note that these options are only for impatient benchmarking! In reality it's almost always a bad idea to run the JIT compilation this aggressively; You're wasting valuable time and memory on JIT-compilation of code that might only be ran a few times. It shows, however, how eventual JRuby performance might be better than you expect based on initial runs.

Let me know whether this works for you.

Hellkite answered 29/1, 2013 at 13:48 Comment(0)
X
3

Upgrade to jruby 1.6.8 or jruby 1.7.x with JAVA 7!

Awesome performance.

We had the same issue and its tremendously fast now (with just switching the versions).

Xylophagous answered 13/12, 2012 at 11:23 Comment(1)
I have the same bad performances. Tried java 7 & Jruby 1.7, a fresh rails app is more slower than a strong current project with MRI. Erg.Nepheline

© 2022 - 2024 — McMap. All rights reserved.