Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Whole New World: Rails on the JVM with JRuby!

headius
April 24, 2023

A Whole New World: Rails on the JVM with JRuby!

You probably know about JRuby. You might know it runs Rails. But why?! What does the Java platform do for Ruby and Rails developers that we can't get from regular Ruby? This talk will show how JRuby's integration with the JVM opens up new worlds for Rails developers.

Delivered at RailsConf 2023

headius

April 24, 2023
Tweet

More Decks by headius

Other Decks in Programming

Transcript

  1. Who Am I • Charles Oliver Nutter • @headius(@mastodon.social) •

    [email protected] • JRuby developer since 2004 • Full-time JRuby and JVM language advocate since 2006
  2. What is JRuby? • An implementation of Ruby atop the

    Java Virtual Machine • Ruby implementation fi rst, JVM language second • Many bene fi ts from JVM ecosystem • Ruby code should "just work" • Different extension API, no forking, parallel threads • www.jruby.org
  3. Ruby Compatibility • JRuby 9.4 is out now! • Ruby

    3.1 compatible, 98% of language specs passing • Nearly complete core + stdlib features from 2.7, 3.0 and 3.1 • JRuby 9.3 (Ruby 2.6 compat) • Maintenance through 2023 as needed • Compatibility before performance! • Now we can refocus on optimization again
  4. Ruby 3.2 Coming Soon! • Checklist issue: jruby/jruby#7517 • You

    can help us add missing features! • Hopefully release 3.2 compatibility in the next 6 months
  5. Why JRuby? • JVM GC, JIT, concurrency scales Rails extremely

    well • Rich tools for monitoring, pro fi ling, debugging • Wide platform support: desktop, server, mobile • Zero-compile cross-platform GUI support • Java ecosystem moving fast, with thousands of excellent libraries
  6. JRuby Install • Install a JDK • Java 11+ recommended,

    there's many distributions out there • Java 8 supported for 9.4 and lower • Install JRuby • Recommended: system package, Ruby installer, Docker image • Download tarball/zip or Windows installer
  7. Test it out! [] ~ $ rvm use jruby Using

    /Users/headius/.rvm/gems/jruby-9.4.2.0 [] ~ $ irb >> runtime = java.lang.Runtime.runtime => #<Java::JavaLang::Runtime:0x64a896b0> >> runtime.available_processors => 8 >> runtime.free_memory => 91420584 >>
  8. JRuby Runs Rails! • Since 2007! • "Are there JRuby

    users running Rails applications?" • Oh yes! And at large scale! • Bene fi t from the JVM, libraries, languages • Great way to scale large Rails apps today!
  9. Rails 7 • Rails 7 works on JRuby 9.4! •

    activerecord-jdbc for JRuby: SQLite, MySQL, PostgreSQL • Version 60.0 for Rails 6, 70.0 for Rails 7, etc • Oracle, SQL Server, DB2, are available, may need updates • Performance and compatibility looking good!
  10. Rails 7 actioncable: 203 runs, 921 assertions, 0 failures, 10

    errors actionmailbox: 92 runs, 238 assertions, 0 failures, 0 errors actionmailer: 230 runs, 516 assertions, 0 failures, 1 errors actionpack: 3550 runs, 16802 assertions, 1 failures, 1 errors actiontext: 80 runs, 145 assertions, 7 failures, 2 errors actionview: 2424 runs, 5395 assertions, 2 failures, 4 errors activejob: 368 runs, 837 assertions, 0 failures, 0 errors activemodel: 966 runs, 2853 assertions, 5 failures, 0 errors activestorage: 392 runs, 1121 assertions, 0 failures, 0 errors activesupport: 5188 runs, 12926 assertions, 43 failures, 28 errors 99% passing!
  11. Minimal Con fi g Changes • Generate a new app,

    Rails will use JRuby defaults • Use threads in Puma instead of workers • 2n+1 is a good rule of thumb • Make sure to increase DB connections as well • Existing app: try bundling, replace unsupported libs • Let us know! We can prioritize adding JRuby support!
  12. Scaling Rails • Classic problem on CRuby/MRI • No concurrent

    threads, so we need worker processes • Processes duplicate runtime state and waste resources • JRuby is the answer! • Multi-threaded single process runs your entire site • Single process with leading-edge GC uses resources better
  13. Baseline Rails App • Scaffolded "blog" application on PostgreSQL, Puma

    • IBM VPC instance: 8 vCPU, 32GB • CRuby 3.2, 16 workers • JRuby 9.4: 16 threads • Database, siege benchmark driver on same instance
  14. Workers vs Threads • Workers duplicate a lot of work

    • N * GC overhead, single large heap is better • N * JIT overhead and memory usage • Unavoidable to have some duplicated memory • JVM and JRuby support real parallel threads • One process, one GC, one JIT scales all the way up
  15. Caveats • PostgreSQL local via Docker (<5% overhead) • Siege

    benchmark driver also local (<5% overhead) • Very minimal blog app, full end-to-end requests • JRuby tuning and warmup time are important
  16. Requests per second 0 450 900 1350 1800 60s siege

    iteration 1 2 3 4 5 6 7 JRuby 9.4 CRuby 3.2
  17. requests per second (higher is better) 0rps 450rps 900rps 1350rps

    1800rps 1,280rps 1,705rps JRuby 9.4 CRuby 3.2
  18. Memory • Baseline • JRuby: 3.4GB RSS • CRuby: 16x

    103MB = 1.6GB • With tuning options • JRuby with 300MB heap: 955MB • CRuby YJIT: 16x 125MB = 2GB
  19. Requests per second 0 450 900 1350 1800 60s siege

    iteration 1 2 3 4 5 6 7 JRuby CRuby 3.2 JRuby 300MB heap CRuby 3.2 + YJIT
  20. requests per second (higher is better) 0rps 450rps 900rps 1350rps

    1800rps 1,550rps 1,643rps 1,280rps 1,705rps JRuby 9.4 CRuby 3.2 JRuby 300MB heap CRuby + YJIT
  21. JRuby on Rails Scales! • More requests per second with

    lower latency • Lower memory usage beyond 8-10 concurrent users • Deploy anywhere that has a JVM (which is basically everywhere) • Leverage JVM tools to monitor and optimize
  22. True Story • Large Rails application using 40 xlarge on

    EC2 • 40 worker processes per server • 100k-150k req/min, 50-75ms response times • Migrated app to JRuby, made more use of threading • Down to 10 xlarge, 75% cost reduction • Consistently over 150k req/min, 30ms response times $
  23. Deploying JRuby the Ruby Way • Typical servers, devops tools

    in Ruby work fi ne • Usually no compilation required; install and go • Scales great with Puma • Rails using Puma by default • Small frameworks (e.g. Sinatra, Roda) scale even better
  24. Deploying with Warbler • gem install warbler ; warble <myapp>

    • Bundle your app + libs + JRuby into a single fi le • Hand off to ops to deploy or run as executable (w/ built-in server) • One click deploy to Java clouds: • Elastic Beanstalk, Google AppEngine, etc • github.com/jruby/warbler
  25. So much more! • JVM and JRuby have much more

    to offer • We'll cover a few areas that make JRuby stand out • Some of these are early or experimental, but very exciting!
  26. JDK Flight Recorder • Low-overhead monitoring and pro fi ling

    for JVM • Always-on monitoring <1% overhead • Active pro fi ling around 5% overhead • Track memory, heap usage, GC, hot methods, JIT activity • Think New Relic, AppSignal, Sentry.io... but built-in and FREE
  27. JDK Mission Control • GUI control center and visualizer for

    Flight Recorder data • Start and manage recordings • Save, load, and browse recorded data • https://adoptium.net/jmc/
  28. GUI Libraries • Swing, built into JDK • Clean, cross-platform,

    easy to build simple UIs • Scalable Windowing Toolkit (Eclipse SWT) • Native widgets, WebKit browser component, rich ecosystem • JavaFX (via JRubyFX, github/jruby/jrubyfx) • Scene-based, vector drawing, event-driven modern UI library
  29. Glimmer • Glimmer GUI DSL • Multiple backends (SWT, GTK,

    ...) • JRuby + SWT is the most mature • JRuby makes cross-platform GUI much easier! • Works same everywhere • GUI libraries shipped with gem
  30. Ruboto: JRuby on Android • ruboto.org • Actively used for

    commercial projects today • Build interface with GUI builder, wire it up with Ruby code • Neglected a bit but being updated for JRuby 9.4 now!
  31. Trying Ruboto IRB • Original was pulled from store because

    it asked for ALL privileges! • Duh, it was a tech demo and REPL • We will republish soon, but search for two packages to download: • Ruboto Core: JRuby and Ruboto framework as a shared package • Ruboto IRB: REPL, editor, example scripts
  32. InvokeDynamic • User-de fi ned binding of methods and values

    • Language decides target based on dynamic lookup logic • JVM optimizes that target like static code • Introduced in Java 1.7 (2011) with input from JRuby • Key to JRuby performance!
  33. InvokeDynamic Performance Times faster than JRuby Java 8 no indy

    0 1.25 2.5 3.75 5 Mandelbrot Red/Black 4.05x 3.92x 3.74x 3.68x 3.72x 1.97x Java 8 indy Java 11 indy Java 17 indy 3.28x CRuby JIT 1.86x CRuby JIT
  34. Indy + Graal JIT? Times faster than JRuby Java 8

    no indy 0 4 8 12 16 Mandelbrot Red/Black 3.13x 15.7x 4.05x 3.92x 3.74x 3.68x 3.72x 1.97x Java 8 indy Java 11 indy Java 17 indy Graal CE indy Escape analysis But not always better
  35. Project Loom • JRuby's fi bers are based on threads

    • Too many, JVM blows up! • Scheduling, resource-intensive • Loom brings fi bers to JVM • Easily handles thousands of fi bers • Faster context-switching
  36. 5.times do t = Time.now # create 100k fibers ary

    = 100_000.times.map { Fiber.new { } } # resume and complete 100k fibers ary.each(&:resume) p Time.now - t end
  37. $ jruby fiber_test.rb [7.603s][warning][os,thread] Attempt to protect stack guard pages

    failed (0x00007fc240a00000-0x00007fc240a04000). # # A fatal error has been detected by the Java Runtime Environment: # Native memory allocation (mprotect) failed to protect 16384 bytes for # memory to guard stack pages # # An error report file with more information is saved as: # /home/headius/work/jruby93/hs_err_pid75149.log # # If you would like to submit a bug report, please visit: # https://bugreport.java.com/bugreport/crash.jsp # Aborted (core dumped) 😩
  38. Project Panama • Foreign function interface (FFI) • With JVM

    help to make direct calls • Foreign memory API • JVM-assisted access, lifecycle • API extraction from C/++ headers • Save time setting up bindings
  39. jextract code generator • Writing bindings using FFI or Fiddle

    is still challenging • Parameter sizes, struct layout, in and out values, pointers • Differences across platforms • jextract: produce Panama/FFI stub code from a C header fi le • Call that stub code from JRuby... easy FFI for all!
  40. JRuby Future • JRuby 9.4 continues to stablize • Many

    production users already! • Big optimization work coming the rest of this year • JRuby 9.5: Java 17 minimum, Ruby 3.2 support, many optimizations • Lots of new JVM features to leverage • Looking into native compilation, snapshotting for fast startup!
  41. JRuby on Rails Future • Rails 7 support is looking

    great! • We are caught up again, will keep tracking updates • As your app grows, JRuby can help you scale • Reduce resources, save money 🤑 • Let's talk about running your app on JRuby!
  42. Thank You! • Charles Oliver Nutter • [email protected] • @headius

    • https://github.com/jruby/jruby • https://www.jruby.org