A status update on JRuby, covering compatibility, Rails, and next-gen performance numbers. JRuby is currently the fastest way to run Rails apps, and we're doing work to make it even faster in the future.
2. Hello!
• Charles Oliver Nutter
• headius@headius.com, @headius
• JVM language advocate at Red Hat
• 20-year JVM veteran, 12 years on
JRuby
• Excited to be back in Kyiv!
3. The JRuby Guys
• Shout out to my buddy Tom Enebo
• Just presented at RubyKaigi in
Sendai, Japan
• We've worked together on JRuby for
over 12 years!
4. Beer For You!
• I am a beer lover!
• I brought some American craft
beers to give away!
• Try running something on JRuby,
show me, and take your pick:
• Bender: oatmeal brown ale
• Furious: dark American IPA
• Foggy Geezer: New England IPA
5.
6.
7. What is JRuby
• It's just Ruby!
• Ruby 2.5 compatible, if something's broken tell us
• Supports pure-Ruby gems, many extensions
• We want to be a Ruby first!
• It's a JVM language
• Full access to the power of the JVM platform!
8. Ruby!
• JRuby 9.2 is now Ruby 2.5 compatible
• Modulo a few things we couldn't finish
• You won't notice unless you use some weird edge features
• Primary focus is always on compatibility and experience
• Performance comes along later
10. JRuby 9.2
• Ruby 2.5, of course
• Better support for non-ASCII identifiers
• Method names, constants, symbols...
• Keyword arguments optimizations
• Preparing for new optimizations and JVMs
11. Supporting Ruby Versions
• Checklist based off CRuby's NEWS file
• Update our copy of CRuby's tests and make them pass
• Same process for ruby/spec, our own tests, and key libraries
12. New Feature? You Can Help!
• New features are great opportunities to contribute!
• Learn more about how Ruby and JRuby work!
• Help us keep up with Ruby development!
• Profit!
• We are always standing by on IRC, Gitter, Twitter to help you
13. Library Compatibility
• We also run library tests
• Rails, Rake, RubyGems, ...
• Core Ruby tests will never cover 100% of users
• Rails in particular is a key target
15. JRuby Architecture
• Mixed-mode runtime
• Interpreter runs for a while, gathering information
• Just-in-time (JIT) compiler compiles hot code to JVM
• JVM turns that into optimized native code
• Heavy dependence on JVM to optimize well
• Newer JVM JITs showing great promise!
17. Microbenching
• Very fun to show off, see improve
• Practically useless
• Like judging a person by how much they can bench press
• JRuby has won microbenchmarks for years, never faster on Rails
• Easier to isolate specific measurements
• Great for exploring new runtimes and tech
18. bench_aref
• Testing calls to ary[n]
• Reduced overhead in JRuby 9.2
• String#[] needs to store $~
• We have to track that just in case ary is a String
• JRuby 9.1 deoptimized more than necessary
19. require 'benchmark/ips'
@a = [1]
def foo(a)
a[0]
end
Benchmark.ips do |x|
x.time = 10
x.warmup = 15
x.report("Instantiation") {
a = @a
i = 0; while i < 1_000_000; foo(a); i += 1; end
}
end
20. bench_aref iterations per second (higher is better)
0 iter/s
10 iter/s
20 iter/s
30 iter/s
40 iter/s
JDK10
JRuby 9.1 JRuby 9.2
39.132
30.248
21. InvokeDynamic
• JVM support for dynamic invocation
• Let the JVM see through all the dynamic bits of Ruby
• Added in Java 7, with much input and testing from JRuby
• Steadily improving performance, reducing overhead
• -Xcompile.invokedynamic
• May be default soon!
22. bench_aref iterations per second (higher is better)
0 iter/s
22.5 iter/s
45 iter/s
67.5 iter/s
90 iter/s
JDK10 JDK10 with Indy
JRuby 9.1 JRuby 9.2 JRuby 9.1 JRuby 9.2
89.169
39.132
68.122
30.248
23. Graal
• New JVM native JIT written in Java
• Faster evolution
• More advanced optimization
• Plugs into JDK9+ via command line flags
• Shipped with JDK10...try it today!
24. bench_aref iterations per second (higher is better)
0 iter/s
45 iter/s
90 iter/s
135 iter/s
180 iter/s
JDK10 JDK10 with Indy JDK10 Graal with Indy
JRuby 9.1 JRuby 9.2 JRuby 9.1 JRuby 9.2 JRuby 9.1 JRuby 9.2
172.541
89.169
39.132
100.401
68.122
30.248
25. bench_mandelbrot
• Generate a text Mandelbrot fractal
• See? Useful!
• Test of numeric performance
• Heavy reliance on JVM to optimize
• Graal is especially good to us here
26. bench_mandelbrot.rb
def mandelbrot(size)
sum = 0
byte_acc = 0
bit_num = 0
y = 0
while y < size
ci = (2.0*y/size)-1.0
x = 0
while x < size
zrzr = zr = 0.0
zizi = zi = 0.0
cr = (2.0*x/size)-1.5
escape = 0b1
z = 0
while z < 50
27. bench_mandelbrot total execution time (lower is better)
0s
1s
2s
3s
4s
CRuby 2.5 CRuby 2.6 JIT JRuby JRuby Indy JRuby Indy Graal
0.139s
1.33s
2.95s
3.5s3.57s
33. A Long, Hard Journey
• JRuby first ran Rails in 2006
• Almost as long as Rails has existed!
• Thousands of JRoR instances around the world
• JRuby 9000, Ruby 2.4, 2.5 work slowed down Rails support
• Rails 5.0 not supported for at least a year
• ActiveRecord suffered the most
34. ActiveRecord JDBC
• ActiveRecord atop Java DataBase Connectivity API
• No C extensions, no -devel packages, no headers or compiling
• Rebooted last year to reduce maintenance hassle
• 1:1 match with Rails versions (e.g. Rails 5.1 = ARJDBC 51.x)
• SQLite3, MySQL/Maria, PostgreSQL
• Sharing 90%+ of code with Rails
35. Example: MySQL support
• Old adapter: 1600+ lines of Ruby code
• 50.0 adapter: 284 lines
• More can be removed, moved into Rails
• Reduced Java/JDBC code as well
• 51.0 adapter: only 6 lines had to change!
42. ActiveRecord Performance
• Rails apps live and die by ActiveRecord
• Largest CPU consumer by far
• Heavy object churn, GC overhead
• Create, read, and update measurements
• If delete is your bottleneck, we need to talk
• CRuby 2.5.1 vs JRuby 9.2 on JDK10
48. Scaling Rails
• Classic problem on MRI
• No concurrent threads, so we need processes
• Processes inevitably duplicate runtime state
• Much effort and lots of money wasted
• JRuby is a great answer!
• Multi-threaded single process runs your whole site
49. Measuring Rails Performance
• Requests per second
• ActiveRecord operations per second
• CRuby versus JRuby, various configurations
50. Requests Per Second
• Rails 5.1.6, Postgresql 10, scaffolded view
• 4k requests to warm up, then measure every 10k
• EC2 c4.xlarge: 4 vCPUs, 7.5GB
• Bench, database, and app on same instance
51. Requests per second, full stack scaffolded read on Postgresql
0
325
650
975
1300
JRuby JDK8 Indy JRuby JDK10 Indy CRuby
53. JRuby on Rails Memory
• Single instance is much bigger, 400-500MB versus 50MB
• Ten CRuby processes = 500MB
• Ten JRuby threads = 400-500MB
• May need to tell JVM a memory cap
• For 100-way or 1000-way...you do the math
54. JRuby is the fastest way
to run Rails applications.
57. JRuby Flags
• -Xcompile.invokedynamic
• Enable the use of JVM's InvokeDynamic feature
• Faster straight-line perf, maybe slower startup/warmup
• -Xfixnum.cache=false
• Disable caching -256..256 Fixnum objects to help Graal
• --dev for improved startup time (disables optimization)
58. Getting Graal
• Download JDK10, it's in there
• -XX:+UnlockExperimentalVMOptions
-XX:+EnableJVMCI
-XX:+UseJVMCICompiler
• Put in JAVA_OPTS or prefix with -J at JRuby CLI
• Download "GraalVM" as your JDK
• Commercial product, but maybe that's your thing
59. JDK10 Warnings
• JDK9 introduced stricter encapsulation
• We poke through that encapsulation to support Ruby features
• You'll see warnings...they're harmless, but we'll deal with them
60.
61. Thank You!
Charles Oliver Nutter
headius@headius.com
@headius
http://jruby.org
https://github.com/jruby/jruby