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?
JRuby is similar to the standard Ruby interpreter except written in Java. JRuby features some of the same concepts, including object-oriented programming, and dynamic typing as Ruby. The key difference is that JRuby is tightly integrated with Java, and can be called directly from Java programs.
JRuby is an open source implementation of the Ruby programming language for the Java Virtual Machine (JVM). It allows Ruby applications to be run within a Java Virtual Machine and interface with libraries written in either Java or Ruby.
x, JRuby internally needs to require 'java' so it has already required 'java' by the time your expression is evaluated. So technically it is true that "require 'java'" loads Java interoperability, but since our kernel does this now it is largely a no-op by the time you call it (see return value of the require).
TruffleRuby is a high-performance implementation of the Ruby programming language built on GraalVM using the Truffle language implementation framework and the GraalVM compiler. TruffleRuby is one part of GraalVM, a platform for high-performance polyglot programming.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With