Forum: JRuby Slow view rendering and absolutely terrible assets:precompile on JRuby

Posted by John Axel Eriksson (Guest)
on 2012-11-24 16:52
(Received via mailing list)
Hi,

I'm new to the list though I've been using JRuby for around a year - not
for web apps though. We're very happy with the jruby java integration 
and
that was the reason for us to move one of our server apps to jruby 
(which
was previously a java app).

Now, after a year we decided we'd try moving one of our rails apps to 
JRuby
as well for easier deployment, better speed and better integration with
java (for the future). Unfortunately we've hit some seemingly large
obstacles. The first is that view rendering is slower on JRuby, the 
second
is rake assets:precompile.

First, the view rendering - these are some results I've come up with 
trying
to replicate a controller/view we have in our real app. The results here
are generally slightly better than the reality for us and the view
rendering is alot faster in both MRI and JRuby in this test app - but 
the
difference between JRuby and MRI is about the same as in our real app.

I've also only run this on webrick (our real apps run on either unicorn 
or
trinidad depending on ruby vm). The test app can be found here (no need 
for
active_record or any persistence layer to run it):

https://github.com/johnae/jruby-view-rendering

These are my results when testing in MRI and JRuby:

---------------------------------
-- 1.9.3p327 env production --

after 1 request (for "some" warmup - eg. loading code etc)

Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:01:15 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (19.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(19.4ms)
Completed 200 OK in 21ms (Views: 20.3ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:01:16 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (19.5ms)
  Rendered log_entries/index.html.haml within layouts/application 
(19.8ms)
Completed 200 OK in 21ms (Views: 20.7ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:01:17 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (19.6ms)
  Rendered log_entries/index.html.haml within layouts/application 
(20.1ms)
Completed 200 OK in 21ms (Views: 21.1ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:01:18 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (28.4ms)
  Rendered log_entries/index.html.haml within layouts/application 
(28.7ms)
Completed 200 OK in 30ms (Views: 29.6ms)

so, MRI completes the request in 20-30 ms.

after perhaps 40 requests (MRI shouldn't really need much warmup - but
still)

Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:03:28 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (17.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(17.3ms)
Completed 200 OK in 18ms (Views: 18.2ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:03:29 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (19.5ms)
  Rendered log_entries/index.html.haml within layouts/application 
(19.9ms)
Completed 200 OK in 21ms (Views: 20.7ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:03:31 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (17.5ms)
  Rendered log_entries/index.html.haml within layouts/application 
(17.9ms)
Completed 200 OK in 19ms (Views: 18.7ms)


Started GET "/log_entries" for 127.0.0.1 at 2012-11-24 16:03:36 +0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (20.9ms)
  Rendered log_entries/index.html.haml within layouts/application 
(21.3ms)
Completed 200 OK in 22ms (Views: 22.2ms)

so, let's say MRI can complete this request in under 30 ms and usually 
in
around 20 ms.

-- jruby 1.7.0 (1.9 mode) env production --

after 1 request (eg. no warmup really, but should still have loaded some
stuff)

Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:54:37 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (90.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(91.0ms)
Completed 200 OK in 97ms (Views: 96.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:54:38 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (87.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(88.0ms)
Completed 200 OK in 95ms (Views: 94.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:54:40 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (74.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(76.0ms)
Completed 200 OK in 82ms (Views: 81.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:54:56 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (78.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(80.0ms)
Completed 200 OK in 90ms (Views: 89.0ms)

so, here it's around 4 times slower than MRI - jruby can complete the
request in 82-100 ms

after 100 requests (let the jvm warmup some)

Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:56:11 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (37.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(38.0ms)
Completed 200 OK in 40ms (Views: 39.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:56:13 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (43.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(44.0ms)
Completed 200 OK in 46ms (Views: 46.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:56:14 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (32.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(33.0ms)
Completed 200 OK in 36ms (Views: 35.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:56:15 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (44.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(45.0ms)
Completed 200 OK in 48ms (Views: 47.0ms)

ok, better but still slower than MRI - jruby can now complete the 
request
in around 40-50 ms

after 1000 requests (should have warmed up by now)

Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:58:25 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (32.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(32.0ms)
Completed 200 OK in 34ms (Views: 34.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:58:26 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (36.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(36.0ms)
Completed 200 OK in 38ms (Views: 38.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:58:27 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (32.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(33.0ms)
Completed 200 OK in 35ms (Views: 34.0ms)


Started GET "/log_entries" for 0:0:0:0:0:0:0:1 at 2012-11-24 15:58:28 
+0100
Processing by LogEntriesController#index as */*
  Rendered log_entries/_table.html.haml (34.0ms)
  Rendered log_entries/index.html.haml within layouts/application 
(34.0ms)
Completed 200 OK in 37ms (Views: 36.0ms)

ok, even better but still slower than MRI, jruby can now complete the
request in around 30-40 ms
---------------------------------

Now, I know these aren't super-scientific - I've tried to replicate some 
of
the behavior of one of our real apps. The problem is that we see slower
view rendering on jruby overall. In general view rendering has been 
around
half as fast in jruby for us and the feel of the app is that it's a bit
sluggish compared to before. In development it's slightly worse but 
doesn't
matter as much.

My conclusion here is that MRI is faster at completing a request, eg.
latency is lower. Best case for JRuby is that it can reach around 58 % 
of
the speed of MRI. The view rendering of the real app is slower than the
above (since it's doing more). We see MRI completing requests to the
controller/view I've tried to replicate here in around 50-90 ms while 
JRuby
completes them in around 120-180 ms(after warmup). So it seems as if the 
58
% of the speed of MRI still holds true.

I've really tried everything on JRuby. I tried enabling invokedynamic,
tried increasing memory (even tried 2GB where I set xms and xmx both to
2GB). Tried increasing code cache, tried upping permgen. Tried
TieredCompilation, tried UseCompressedOops, tried other garbage
collectors...
Afaik I've exhausted most of the things you CAN do(tried both client and
server modes of course - in production we only run the jvm in server 
mode).
I've tried openjdk 7, tried the Oracle JDK 7 (latest as of a week ago).
Tried downgrading from jruby 1.7 to 1.6.8, tried upgrading haml to a 
beta
version... even tried this test app in ERB which should be faster (I 
still
see jruby being slower using ERB).

So, kind of disappointing results for us. Perhaps I'm missing something 
but
so far JRuby hasn't really been that great for us when running our web
apps. The above tests were done on webrick on both MRI and JRuby but in
production we run on Trinidad (see the same results there).

The other BIG problem we've had is running rake tasks, some of which
complete much
slower on jruby but they at least do complete... while rake
assets:precompile has been... let's say around 100 times slower than MRI 
-
if it completes at all.
We were hoping to use less memory on JRuby than on MRI since we run two
apps on the same machine(on JRuby they both run in the same JVM) - the 
end
result has been the opposite, especially because of assets:precompile, 
we
sometimes run out of memory running that rake task... something that 
NEVER
happened on MRI.
I think we've got ourselves out of the worst of assets:precompile by not
using therhubyrhino (which seems to be completely unusably slow) and 
just
using nodejs for assets compilation. It's still much slower than MRI
though, and still uses lots more memory than MRI.

I really really want to run our web apps on JRuby, but if I can't 
resolve
the above issues I can't really justify it.

We still really like the possibilities of JRuby and we've been running 
our
not-a-webapp but a server-app on JRuby since we must have the java
integration there + we've been really happy with it's performance.

If you have any suggestions - please let me know. Thanks!

/John
Posted by Alex Tambellini (Guest)
on 2012-11-24 19:32
(Received via mailing list)
Try running the cpu sampler in visual vm (http://visualvm.java.net) 
against your app to see what's using up the most time.
Posted by John Axel Eriksson (Guest)
on 2012-11-25 13:11
(Received via mailing list)
org.jruby.RubyThread.lockInterruptibly is where it's spending 70% of 
time
(cpu time there is 0.000 ms though). Most of the cpu time is spent in
org.jruby.util.io.SelectBlob.doSelect().

Not entirely sure how to read the output... I'm not an expert on 
VisualVM
(or the JVM) really. Not seeing haml or anything else showing up at the 
top.
Posted by Keith B. (keith_b)
on 2012-11-25 20:20
(Received via mailing list)
John -

Firstly, I just want to say, wow, you've been amazingly thorough in 
pursuing this problem.

The dramatic differences you're experiencing between MRI Ruby and JRuby 
(especially with rake) make me wonder if there's something going on with 
your Java installation(s). If JRuby were slower at all, I would expect 
it to be only a little slower, nowhere near your experience.

Is there anything you can tell us about the machine on which you're 
testing (e.g. OS)?

Is the total memory enough to support the increased settings you tried? 
I tried using a ridiculous number, and it didn't complain:

>java -Xmx20000000m -jar sample-rails-app.war

Also, with whatever memory you have to work with, I'd suggest allocating 
almost all of it to heap rather than stack.

Is it possible that JRuby and/or Java are installed on volumes that are 
slower than the one on which MRI Ruby is installed?

You report similar problems on the production machine; is this the case 
for both the rails rendering and the rake task?  Does the speed 
difference also occur when running other Ruby apps, subtracting the JVM 
startup time, in my case, 3.19 seconds:

>rvm 1.9
>time ruby -e ""
ruby -e ""  0.03s user 0.01s system 8% cpu 0.474 total

>rvm jruby
>time ruby -e ""
ruby -e ""  3.22s user 0.19s system 182% cpu 1.868 total

Are you using rvm, by the way?  Using SELinux or anything similar that 
might be inserting itself into the running of the process?

Regarding the Rails app benchmark, I don't know how significant, but I 
wonder if testing the JRuby app on a Java web server would be a fairer 
comparison than using Webrick on JRuby.  Webrick is known to be slow, so 
running the web server code in Ruby instead of Java may unfairly bias 
your results. In order to make running a Java web server easy, I tried 
running warble executable on your project, but when I ran the resulting 
war file I got this error:

>java -jar jruby-view-rendering-master.war
Nov 25, 2012 1:34:12 PM winstone.Logger logInternal
INFO: Beginning extraction from war file
Nov 25, 2012 1:34:17 PM winstone.Logger logInternal
WARNING: No webapp classes folder found - 
/private/var/folders/ll/nyv2lhd08xl8lf0059bmbrw80000gp/T/warbler5205388911019780837webroot/jruby-view-rendering-master.war/WEB-INF/classes
Nov 25, 2012 1:34:17 PM winstone.Logger logInternal
INFO: Winstone shutdown successfully
Nov 25, 2012 1:34:17 PM winstone.Logger logInternal
SEVERE: Container startup failed
java.lang.ClassCastException: org.jruby.rack.RackFilter cannot be cast 
to javax.servlet.Filter
...

Also, when I tried to run rake assets:precompile in either MRI 1.9.3 or 
JRuby 1.7, I got:

>time rake assets:precompile
rake aborted!
Don't know how to build task 'assets:precompile'

I didn't get either error when using a 'rails new' -ly generated Rails 
app.  I'm not really a Rails developer (yet) though, so I may be missing 
something simple.  Hope you don't mind the stabs in the dark, I'm hoping 
something might pay off.

- Keith

---
Keith R. Bennett
http://about.me/keithrbennett
Posted by John Axel Eriksson (Guest)
on 2012-11-26 09:53
(Received via mailing list)
Sure. My development machine is a Macbook Pro Retina Quad-Core Intel 
Core
i7 with 16 GB Ram - OS X 10.8.2. The production machine is an Ubuntu 
12.04
7 GB Ram running on EC2 (so - virtualized). I have the same problem in 
dev
as in prod.

JRuby is installed on the same volume as MRI. In dev that is a 256 GB 
SSD,
in prod it's an EBS-backed volume. Heh - funny how my development 
machine
is probably faster than my production server.

The test app on github isn't for testing assets:precompile (sorry, I 
might
have been unclear) - it's ONLY for the view rendering part. As I said - 
I'm
testing on webrick, but the original concern came from running on either
Unicorn or Trinidad (Tomcat wrapped in a bit of ruby). In production we 
run
on Trinidad. It was simply easier to run on webrick since the results 
were
more or less the same as on Trinidad. I've also tested on Torquebox with
about the same results - eg. MRI is faster.

I'm not using RVM but rbenv in both dev and prod. The slowness (100x
slower) running assets:precompile seem to be mostly due to therhubyrhino
running completely unoptimized as reported by Charles Nutter here:
https://github.com/cowboyd/therubyrhino/issues/23. Of course, one-off
commands such as rake will be slower than MRI - but 100x slower while 
using
10x the ram? That's simply unacceptable. As I said, using nodejs for 
assets
compilation together with turbosprockets-rails (
https://github.com/ndbroadbent/turbo-sprockets-rails3) has made it 
almost
bearable... but compared to MRI it's still like night and day. It's 
still
uses LOTS more memory and is in general... perhaps half as fast, 
probably
slower.

So the end result is very mixed. The good stuff is that we get great 
java
integration, pretty awesome deployment possibilities, and a somewhat
simpler deployment. The bad stuff is that the app is slower overall (how 
it
"feels"), and I've got the numbers to back that up, the deployment 
(while
simpler) is MUCH slower and uses LOTS more ram. And I've found out the 
hard
way that Trinidad (and, as I've read, other java server containers) leak
memory on redeploy so the zero-downtime we've enjoyed on unicorn is a 
bit
less "zero" on JRuby (since a full restart of Trinidad is needed every 
now
and then).

Unfortunately, so far, JRuby has meant less good than bad which is the
reason we might move back to MRI and Unicorn for the time being... I 
really
WANT to run on JRuby because of it's potential though. I'm not sure if 
my
experiences are because of some bad configuration on my part or if 
they're
something other people are seeing - and I guess I'm interested in the
experiences of other people who've moved their Rails apps from MRI to 
JRuby.

Thanks,
John
Posted by Anthony Juckel (Guest)
on 2012-11-29 05:03
(Received via mailing list)
On Sun, Nov 25, 2012 at 6:10 AM, John Axel Eriksson <john@insane.se> 
wrote:

> org.jruby.RubyThread.lockInterruptibly is where it's spending 70% of time
> (cpu time there is 0.000 ms though). Most of the cpu time is spent in
> org.jruby.util.io.SelectBlob.doSelect().
>
> Not entirely sure how to read the output... I'm not an expert on VisualVM
> (or the JVM) really. Not seeing haml or anything else showing up at the top.
>
>
That's just part of the IO subsystem, so I doubt that's what's causing 
your
slowdown.  I did some profiling locally to see if I could replicate the
behavior you're seeing, but unfortunately, I can't.  I did isolate the 
view
rendering in my tests though, so perhaps the issue is just further up 
your
stack.

For comparison, here's what I'm seeing (MRI is ruby-1.9.3-p194, JRuby is
1.7.0, JVM is Oracle's 1.7.0_07.  I embedded a controller in a benchmark
and ran through repeated iterations of rendering the view.  1000 warm-up
iterations, then 1000 timed iterations, with results broken into 100
iteration samples.  You can see that even after 1000 iterations, the JVM 
is
still optimizing a bit, but by 2000, seems to have reached a steady 
state.
Not sure why it's taking that long to fully optimize, I haven't dug into
the numbers further than just doing the sampling, but once it does reach 
a
steady state, JRuby is about 30% faster than MRI.  Enabling 
invokedynamic
didn't change performance appreciably, nor did moving the LogEntry.all
allocation to either a single-time shared allocation, or a per-render
allocation.

Either you didn't mention, or I missed it.  What JVM are you running on,
both in your test environment and production?

MRI:
[...truncated a bit, since MRI's performance doesn't change much...]
Sample mean: 0.044296849999999985; Sample stddev: 0.010034992645606094
Sample mean: 0.043826000000000004; Sample stddev: 0.009419012821220481
Sample mean: 0.043669299999999994; Sample stddev: 0.009377437996539747
Sample mean: 0.043847399999999995; Sample stddev: 0.009612958356192684
Sample mean: 0.044089550000000005; Sample stddev: 0.009703262210395235

JRuby:
Sample mean: 0.05607000000000001; Sample stddev: 0.018613699201926466
Sample mean: 0.030839999999999996; Sample stddev: 0.003719237458502387
Sample mean: 0.028590000000000008; Sample stddev: 0.0014361494534084027
Sample mean: 0.02932; Sample stddev: 0.0053689718369403444
Sample mean: 0.028150000000000026; Sample stddev: 0.001479660075623431
Sample mean: 0.028940000000000014; Sample stddev: 0.0026621932174943123
Sample mean: 0.028880000000000013; Sample stddev: 0.004369961745435038
Sample mean: 0.02925000000000002; Sample stddev: 0.0053207711904014535
Sample mean: 0.02742; Sample stddev: 0.0011562740578987733
Sample mean: 0.027309999999999997; Sample stddev: 0.0010019677609281624
Posted by John Axel Eriksson (Guest)
on 2012-11-29 08:49
(Received via mailing list)
Tested on jruby 1.7.0 and jruby 1.6.8, OpenJDK 7 and Oracle JDK 7.
MRI was 1.9.3-p327.
I've tested the actual time shown in the rails logs and the time a 
request takes using curl. In general it's slower on JRuby regardless of 
JRuby version/JDK version, web server or OS. I see the same thing on 
webrick as on Trinidad, same thing on Macbook Pro 15 Retina with SSD/Mac 
OS X 10.8.2 as on Linux Ubuntu 12.04 on EC2/EBS.

The "feel" of the app on jruby in both prod/dev is "more sluggish" on 
JRuby and the numbers back that up.

29 nov 2012 kl. 05:02 skrev Anthony Juckel <ajuckel@gmail.com>:
Posted by John Axel Eriksson (Guest)
on 2012-12-05 15:13
(Received via mailing list)
Last update on this is that we had to give up. JRuby was simply too slow
for us to justify, switching back to MRI was like getting a new server 
with
double everything. It's just ALOT faster. I know this isn't what some
benchmarks claim but it's the truth for us.

Some things on JRuby are so slow that they're completely, utterly
unusable... like rake assets:precompile for example - MRI sometimes 
takes
almost two minutes to compile which to me is unacceptable, JRuby on the
other hand can take anywhere from 15 minutes to infinity (eg. I'm not 
gonna
sit around watching it chug away for more than an hour - that process 
gets
killed). We did everything we could to speed up the assets:precompile, 
for
example, not doing all of it - just the parts we needed, switching to
nodejs as compiler for the assets, using turbosprockets. All those 
helped a
bit but still unusable i.m.o and much much slower and eating MUCH more
memory than MRI(that is compared to MRI without any weird patches to 
make
things go faster).

So - deployment of the app wasn't working for us, we must be able to 
deploy
a new version in at most 2-3 minutes (preferrably faster than that).

Another issue was the overall sluggishness of the app, it just felt alot
slower on JRuby than on MRI. Views rendered in double the time for 
example.

A third issue was the fact that on MRI (just plain old 1.9.3-p125, no
patches) we use quite a bit less memory than Trinidad+JRuby. The app on
Trinidad leaked memory on every redeploy - something that doesn't happen 
on
unicorn. With unicorn we could do real, zero-downtime deploys. On
Trinidad... well, not so much. I didn't dare turning that option on 
since
it leaked ridiculous amounts of memory on "normal" redeploys where 
requests
are paused.

The final decision to go back to MRI was made when we tried out JRuby 
1.7.1
- for some reason the assets were ALWAYS missing on 1.7.1 (even though 
we
could clearly see them sitting there on disk). For some reason
rails+jruby-1.7.1 decided that the hashes of the assets were different 
from
what was on disk. Running assets:precompile a few times (on 1.7.1 - even
the full compile without turbosprockets or any other tricks) was 
useless.
Removing all assets and starting from scratch was useless. Our app was 
just
down. We needed to upgrade to 1.7.1 because of
https://jira.codehaus.org/browse/JRUBY-7008.
Fortunately our first foray into JRuby on Rails was a management app 
that
no customers access - we only use it internally. We wanted to try this 
app
in production first to see what worked and what didn't since this is a 
low
risk app running on only one server.

Basically, moving one of our Rails apps to JRuby meant:

The bad:
Half the performance of MRI rendering views
Sluggish "feel" overall
Unusable assets precompilation (takes "too long to infinity" on JRuby 
even
with every conceivable tweak or hack to the asset pipeline)
Uses a lot more memory than Rails on Unicorn
Leaks memory (eg. needs complete Trinidad restart now and then - which
means downtime)
Frustratingly high memory usage when running command-line tasks (like 
rake
tasks)
Frustratingly slow startup - rake tasks aren't much fun (they're slow on
MRI too i.m.o but JRuby is like 5x-20x as slow, except for assets
compilation which is possibly the worst thing I've ever experienced)
Incompatibilities/bugs (yeah well - MRI has bugs too)
JRuby 1.7.1 + Rails wouldn't render assets anymore (claimed they didn't
exist)

The good:
Java integration (something we may need)
A better concurrency story

I'm really sorry that this was our first experience running Rails on 
JRuby
- we really wanted it to work and work faster, deploy easier, be less
buggy, have a better concurrency story. None of those (except for maybe
concurrency) were true - rather the opposite. Before moving the app to
JRuby I had read a few success stories, some of which claimed that view
rendering would be faster on JRuby. I did know about slow startup times,
but it was in production it that got really frustrating for us. And 
again -
assets:precompile isn't usable on JRuby at all while on MRI it's at best
bearable. I wouldn't ever accuse the rails asset pipeline compilation of
being fast.

I don't want to be too hard on the JRuby devs - I know how much hard 
work
is behind JRuby and I really like the whole idea of running on the JVM 
(and
we still run a non-rails, non-web app on JRuby with success)... I just
wanted to let you know that our experience moving a Rails app onto JRuby
was far from pleasant.

I don't understand how we could have such a bad experience when I've 
heard
so much good about JRuby and JRuby on Rails in talks, on blogs and other
places. I also know of several places running JRuby on Rails in 
production.
Either they keep silent about their issues or... I don't know - I'm 
still
open to suggestions and I guess something, somewhere could possibly have
been tweaked in some way - though we've been running the app on jruby 
for
three weeks or more in production and I've been tweaking and hacking 
away
quite heavily with mostly nonexistent good results, we've tried OpenJDK 
6,
OpenJDK 7 and Oracle JDK 7... We were out of ideas and options when we
switched back to MRI.

Thanks,
John
Posted by Patrick Mahoney (Guest)
on 2012-12-07 18:25
(Received via mailing list)
On 24.11.2012 09:51, John Axel Eriksson wrote:

> The other BIG problem we've had is running rake tasks, some of which
> complete much
> slower on jruby but they at least do complete... while rake
> assets:precompile has been... let's say around 100 times slower than
> MRI

This has been a source of pain for me as well.  I did some profiling
work, and
found much time being spent dealing with exceptions-as-flow-control.
This
anti-pattern is a performance drain on MRI, but is even more apparent
on JRuby.

I'd been meaning to come up with a better benchmark for sometime now,
and here
it is:

https://gist.github.com/4234608
https://github.com/pmahoney/assets_comp_perf

Still a lot of improvement to be made (though even MRI is painfully
slow).

I admit I don't quite understand why "assets:precompile" is hardly
faster
than "assets:clean assets:precompile", so perhaps I don't know enough
to even make a proper benchmark...  I hope to be able to keep digging
into this, but that seems unlikely any time soon.

--
Patrick Mahoney
Posted by Tim Uckun (Guest)
on 2012-12-10 15:02
(Received via mailing list)
Hey guys.

I just want to pick up this thread again.  It has been real
interesting to read about the problems people have had with
Jruby+Rails  and it's looking like it's just not a good fit at all.
So is this the general consensus then? That Jruby is not a good fit
for rails? Are there alternatives to make the view rendering faster?
Has anybody tried using markaby or something similar? Haml? What about
the asset pipeline? Any alternatives?  What about other frameworks
like sinatra?

I think for the future googlers we should clean this thread up. Either
conclude that jruby should be avoided with rails or find the magic
incantation that will make it work.

Thanks.
Posted by Keith B. (keith_b)
on 2012-12-10 15:44
(Received via mailing list)
I'm not knowledgeable about the issues raised in this thread, but I do 
know that JRuby is used with Rails in production at sites all over.  A 
week or two after giving a JRuby talk at Bangkok's Rails/JavaScript 
meetup, a European developer told me he switched his business' site to 
use JRuby and it greatly simplified his operation.  He seemed happy with 
the performance as well.

I'm not at all discounting the experiences recounted on this thread, I'm 
just saying that, based on what I've seen, it would be inaccurate to say 
that JRuby and Rails do not work well together.

It would certainly be nice if one/some of the authors addressed this 
thread.  I did raise the issue with Charlie Nutter when he spoke at Ruby 
Hangout (on YouTube at 
https://www.youtube.com/watch?feature=player_embed..., 
sorry, I don't know where in the video this is), and he acknowledged 
that there are issues.

- Keith

---
Keith R. Bennett
http://about.me/keithrbennett
Posted by Benjamin Browning (Guest)
on 2012-12-10 16:30
(Received via mailing list)
Here's a baseline time for JRuby and assets:precompile for a Rails 
application with a small to medium amount of assets on my local system:

$ time rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile

real    2m22.891s
user    4m30.941s
sys     0m6.728s


There are several options for speeding this up. If your JVM supports it, 
run JRuby in 32-bit mode - "-J-d32". Try turning off all compilation and 
running purely interpreted - "-X-C". Combining these options cuts a 
large percentage of the time off in my tests.

$ time JRUBY_OPTS="-J-d32 -X-C" rake RAILS_ENV=production 
RAILS_GROUPS=assets assets:precompile

real    1m41.990s
user    1m52.771s
sys     0m2.969s


If you have the 'node' binary available on your system, you can tell 
Rails to use that instead of therubyrhino for asset compilation and cut 
off even more time.

$ time EXECJS_RUNTIME='Node' JRUBY_OPTS="-J-d32 -X-C" rake 
RAILS_ENV=production RAILS_GROUPS=assets assets:precompile

real    0m29.981s
user    0m32.636s
sys     0m2.880s


If you don't have the node binary available then you can still gain a 
large boost by switching from uglifier to closure-compiler for 
minification by setting config.assets.js_compressor = :closure in 
config/application.rb. The size of the result assets is almost 
identical, at least in my case.

$ time JRUBY_OPTS="-J-d32 -X-C" rake RAILS_ENV=production 
RAILS_GROUPS=assets assets:precompile
real    0m44.692s
user    1m16.724s
sys     0m3.262s


For reference, Ruby 1.9.3 can compile assets for the above application 
in 14.314 seconds. With a bit of tweaking I got JRuby from 143 seconds 
down to 30 seconds. Still not as fast as Ruby 1.9.3, but much closer.


Ben
Posted by Richie Vos (Guest)
on 2012-12-10 16:56
(Received via mailing list)
As someone who uses jruby on rails, but without views, this is really an
interesting thread. Could someone put together a simple github repo that
reproduces this, with the speed ups?

I'd love to see that plus a blog article. Given how prevalent rails is,
this seems like an important limitation to make widely known. If only so
the next dev knows it's not her fault.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.