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

Scaling Ruby with JRuby

headius
December 09, 2022

Scaling Ruby with JRuby

A talk on JRuby and how to scale Ruby and Rails applications using it. Delivered at RubyConf Thailand in Bangkok, December 9 2022.

headius

December 09, 2022
Tweet

More Decks by headius

Other Decks in Programming

Transcript

  1. Me • Programming my whole life • Professionally since 1996

    • JRuby since 2006 • [email protected] • @headius(@mastodon.social)
  2. Thank You Yarden! • I got to speak at RubyConf!

    • Tomorrow's JRuby keynote • "Ruby & JVM: A Love Story" • Really cool talk about her experiences using and building apps with JRuby! • @YardenLaif
  3. 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 • https://www.jruby.org/
  4. 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
  5. Ruby 3.2 Coming Soon! • We will set up another

    checklist issue • You can help us add missing features! • Hopefully release 3.2 compatibility in the next 6 months
  6. Why Ruby on JVM? • Widely deployed and widely supported

    runtime • Excellent JIT, GC, concurrency, and platform support • Tens of thousands of libraries • Rich tools for monitoring, pro fi ling, debugging • "Write once, run anywhere": JRuby works on many platforms
  7. Fun Stuff • 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
  8. 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
  9. Try it out! [] ~ $ rvm use jruby Using

    /Users/headius/.rvm/gems/jruby-9.4.0.0 [] ~ $ irb :001 > runtime = java.lang.Runtime.runtime => #<Java::JavaLang::Runtime:0x64a896b0> :002 > runtime.available_processors => 8 :003 > runtime.free_memory => 91420584 :004 >
  10. 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!
  11. Getting Started • Generate a new app, Rails will use

    JRuby defaults • Couple gotchas with Rails 7, we can help • 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
  12. Rails 7 • Rails 7 works on JRuby 9.4! •

    ActiveRecord for JRuby needs some updates • Mostly small changes to our ActiveRecord JDBC adapter • Performance and compatibility looking good! • Couple gotchas right now but we're working through them
  13. 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!
  14. activerecord-jdbc-adapter • Version-matched to Rails • 60.0 for Rails 6.x,

    70.0 for Rails 7.x, etc • 70.0 in progress • sqlite, mysql working pretty well, gems are out there • sqlite: 7745 runs, 25040 assertions, 32 failures, 14 errors • postgresql needs more updates, coming soon
  15. What Matters to You? • Straight-line performance? • High concurrency?

    • Startup time? • Warmup time? • Memory size? • Optimizing for only one of these can penalize the others
  16. Benchmarks • Benchmarks are very situational • What looks good

    in a microbench may not translate to production • Two example benchmarks • railsbench, small Rails blog on SQLite, no web server, tight loop • Rails blog on MySQL, end to end through Puma
  17. railsbench • Based on simple scaffolded blog app • SQLite

    database, single thread, all in one process • No web server, no connections, just loop on requests • Good for analyzing Rails core framework performance • Not great for real-world end-to-end measurement
  18. The Players • Ruby 3.1.2 with and without --yjit •

    Truf fl eRuby 22.2 JVM CE • Newer versions may be better • JRuby 9.4 on Java 17
  19. time to run 2000 requests (lower is better) 0 550

    1100 1650 2200 Time 1,460ms 1,550ms 1,704ms 2,152ms CRuby 3.1 CRuby 3.1 yjit Tru ffl eRuby JRuby
  20. Memory Footprint • More complex runtimes take more memory •

    Different GC strategies take more memory • CRuby has been optimized for startup time and memory use • Super valuable but may not help server apps
  21. Warmup Time • Optimizing runtimes just take longer to warm

    up • Code needs to be pro fi led, analyzed, compiled • GC needs to fi nd sweet spot for heap size, generations • Known issue, but we and JVM folks always try to improve • Pre-warm new deploys (or just accept it will start off slower) • JVM tooling to bootstrap into a warm VM
  22. Warmup Over Time 0ms 450ms 900ms 1350ms 1800ms Iteration (2000

    requests each) 1 2 3 4 5 6 7 8 9 10 CRuby 3.1 yjit
  23. JRuby Architecture Ruby (.rb) JIT Java Instructions (java bytecode) Ruby

    Instructions (IR) parse interpret interpreter interpret C1 compile native code better native code java bytecode interpreter execute C2 compile Java Virtual Machine JRuby Internals deoptimize Performance improves the longer your app runs
  24. Warmup Over Time 0ms 5000ms 10000ms 15000ms 20000ms Iteration (2000

    requests each) 1 2 3 4 5 6 7 8 9 10 CRuby 3.1 yjit JRuby
  25. Warmup Over Time 0ms 6000ms 12000ms 18000ms 24000ms Iteration (2000

    requests each) 1 2 3 4 5 6 7 8 9 10 Tru ffl eRuby
  26. Warmup Over Time 0ms 7500ms 15000ms 22500ms 30000ms Iteration (2000

    requests each) 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 CRuby 3.1 yjit Tru ffl eRuby JRuby
  27. Benchmarks Lie • The only benchmark that matters is your

    code • Your code is probably not requesting the same posts in a loop • We can make this a bit more real • Full end-to-end: Puma web server, MySQL backend • External request driver (siege) • Max out CPU (high concurrency)
  28. Scaling Rails • Classic problem on MRI • No concurrent

    threads, so we need processes • Processes duplicate runtime state and waste resources • JRuby is the answer! • Multi-threaded single process runs your entire site • Single process with solid GC uses resources better
  29. End-to-end Rails Blog • Scaffolded "blog" application on MySQL •

    Local i7 laptop • CRuby 3.1: 16 workers, 2 threads each • JRuby 9.4: 32 threads • Truf fl eRuby: 32 threads but had issues
  30. Setup • Local everything including benchmark driver • MySQL in

    a Docker container • Scaffolded app is super minimal • Using siege: 16 concurrent, 10s intervals, benchmark mode • Warmup time is a thing...
  31. requests per second (higher is better) 0rps 1500rps 3000rps 4500rps

    6000rps 3m 5,160rps 668rps 2,361rps 2,070rps CRuby 3.1 CRuby 3.1 yjit Tru ffl eRuby JVM CE JRuby
  32. Requests per second, 10s siege runs (higher is better) 0

    1500 3000 4500 6000 1 2 3 4 5 6 7 8 9 10 CRuby 3.1 CRuby 3.1 yjit JRuby
  33. 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
  34. JRuby Future • JRuby 9.4 is out! • Try it

    out, report issues, submit a PR! • Ongoing Rails 7 updates • Big optimization work coming in the next year • New JVM features • Native fi bers! Built-in FFI!
  35. Thank You! • Charles Oliver Nutter • [email protected] • @headius(@mastodon.social)

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