Charles Nutter

JRuby: The Road to Ruby 2.6 and Rails 6

Over the past six months, the JRuby team has been working on filling in edges: getting refinements working well, porting C extensions, and getting well-known applications running. At the same time, we always try to push forward on performance and general compatibility. In this talk, we'll cover recent work to support Rails 6 and Ruby 2.6. We'll show off a major Rails application running on JRuby. And we'll show you how you can help us keep JRuby moving forward.

RubyKaigi 2019 https://rubykaigi.org/2019/presentations/headius.html#apr20

RubyKaigi 2019

00:00:01.190 All right, we will get started and let folks filter in here from lunch as we get going.
00:00:07.560 We're going to give you a little update on where we stand with JRuby, how things are looking in terms of compatibility and performance, and how we are getting ready to support Ruby 2.6 and Rails 6.
00:00:14.820 We are the JRuby co-leads, and we've been working on this project full-time for 11 to 12 years now, which is kind of amazing.
00:00:21.510 We've had sponsors like Red Hat who have been willing to keep this project going. In the past, we were very happy to have Sun Microsystems support a lot of our efforts. So, we are really excited about being able to continue to work on JRuby.
00:00:35.579 Before we continue, I want to mention something important. A good friend of ours, one of the earliest contributors to JRuby, has been arrested and is currently on a 90-day pretrial detention in Ecuador. He was a friend of Julian Assange, which apparently was enough for them to haul him away. He lacks evidence against him, and it’s really a horrible and illegal holding of a good friend of ours. Please search for 'Free Our Beanie' on Twitter, where you can find support groups and fundraisers to help get the word out.
00:01:14.220 Alright, so what is JRuby? I'm guessing most folks here probably have some pretty good idea of what JRuby is, but it's important to emphasize that we want JRuby to be as much of a drop-in replacement for CRuby as possible.
00:01:30.630 We strive to keep compatibility solid and to ensure that all pure Ruby gems work well or have extensions available. We also try to keep a JRE version and want to be a Ruby implementation.
00:01:44.189 Yet, we also have the benefits of running on top of the JVM, which provides the power of great garbage collectors, native kits, and everything else.
00:02:01.170 Let me go over the roadmap of where we're at with JRuby. In the master branch, we have the 9.2 series that supports Ruby 2.5. Last week, we released version 9.2.7. I'll talk about one feature that came with 9.2.7, and next month we plan to release 9.2.8.
00:02:20.770 We've decided to retire JRuby 9.1, which was our 2.3 support. We now have a Ruby 2.6 branch. We are currently pondering whether we should put out Ruby 2.6 support or wait for the next significant release that will presumably be Ruby 2.7.
00:02:41.890 We actually do have a precedent for this: we skipped Ruby 2.4 without many complaints. The reason we want to wait is that we want to spend more time enhancing and making JRuby better. Having multiple support branches consumes a lot of effort.
00:03:06.820 Recently, while working within the 9.2.7 time frame, we've done a large amount of work to get refinements working properly again. We've started to see them appear more often and in key libraries we intend to support. It was necessary for us to catch this up.
00:03:40.370 In JRuby 9.2.7, which we released a couple of weeks ago, refinements are nearly perfect. There are only a few minor errors in the CRuby test refinements script, but these are odd edge cases that almost no one ever encounters. For that release, we were in the 99% range of compatibility with refinements.
00:04:09.330 We’ve also made further improvements to enumerators and fibers—specifically, enumerator dot next, which uses fibers under the hood. Up until the 9.2.8 release, enumerators had their own implementations of fibers and had some bugs that needed repair.
00:04:40.370 Additionally, we are working on reducing the overhead of fibers and are closely examining a new project from the OpenJDK called Project Loom. This will bring real native co-routines and fibers to the JVM, allowing us to spin up thousands or even hundreds of thousands of fibers like you can in CRuby without needing to back each one with a native thread.
00:05:17.840 The final significant project we are currently undertaking is a reboot and rewrite of our internal load and require logic. This is motivated by a desire for improved startup time. We have been doing too much work while performing file searches for requires and such.
00:05:49.890 There is a cache in CRuby that’s been around for years and speeds up loading, and we’ve never implemented a similar cache in JRuby. Also, projects like Siterelated are doing excellent work in bringing more formalized code loading and reloading to Ruby applications.
00:06:12.830 We really need to fix up some features in JRuby related to autoload and elsewhere, especially with respect to Rails compatibility and performance. It’s going to take some time, but we should have all of the require and load issues resolved within the next couple of releases.
00:06:45.080 One of the main reasons people face difficulties adopting JRuby has always been the startup time. We aim to be a drop-in replacement for CRuby, supporting the same command-line tools, server frameworks, and development flows that developers are used to.
00:07:15.280 This becomes quite challenging when we have startup time issues in applications because running quick migrations or rake tasks often takes considerably longer in JRuby.
00:07:43.290 For the past twelve years, we have been continuously working to improve startup time. Currently, this is a sort of state of the art for where we stand.
00:08:06.650 Why is this such a difficult problem for us? CRuby benefits from the fact that all the code running when you start booting an application is written in C. The parser, compiler, and interpreter for those instruction sequences are mostly hot and fast C code.
00:08:50.720 In contrast, JRuby executes on the JVM where everything begins cold. The JVM has to interpret everything as bytecode before it turns into native code. So, while JRuby can speed up operations significantly when repeated in the same JVM, the initial startup time is less than optimal.
00:09:18.540 We are working on various strategies to address this issue. A few graphs illustrate our current situation compared to CRuby. As presented, the timings reveal that CRuby is generally considerably faster.
00:09:51.300 By switching to more severe benchmarks, such as running a gem list command on a local JRuby repository, we start to see the JRuby runtime struggles. Booting JRuby parts written in Ruby takes longer because everything starts out cold.
00:10:27.170 Even for a basic command like '-e 1', this shows how significant the cold start effect is with JRuby; we see that it easily exceeds a second. However, if we set JRuby to run multiple times within the same JVM, it performs significantly better as the JIT optimization begins to kick in.
00:10:58.300 Another interesting measure involves executing gem version commands, which load various Ruby gems necessary for the version information. This consumes considerable time due to the overhead involved in loading all that information.
00:11:26.920 It’s important to note that gem list commands are among our worst cases because this involved primarily a lengthy series of eval calls and does not allow for JIT optimization.
00:11:59.480 As you see from these benchmarks, the 10th iteration starts to get closer to the CRuby numbers. We are seeking ways to get the JVM to pre-optimize this in the future. Over the years, we've had various workarounds, including disabling our JIT to improve startup times.
00:12:34.030 Running on Java 11 has also introduced new features that significantly impact our startup time, resulting in higher initial delays.
00:12:47.940 But using options like class data sharing allows the JVM to preload parts of JRuby, contributing to a shorter startup time. OpenJ9, a new open-source JVM from IBM, supports 'QuickStart' mode that aims to reduce boot time significantly.
00:13:16.950 All in all, while we're pleased with the timeline of optimizations, we recognize that we’re still at a disadvantage relative to CRuby and will seek to make further improvements.
00:13:51.050 To summarize: while we do see improvements, there are still challenges and future opportunities while utilizing JRuby. Moving into large-scale applications, like web development, is a major focus for JRuby, especially with Rails.
00:14:27.740 Many companies are deploying JRuby in production, running entire sites efficiently on clusters that range from 30 to 50 machines, particularly in environments like government institutions and banks.
00:15:06.920 As these features evolve, JRuby on Rails enhances the efficiency of many applications, particularly where existing infrastructure is primarily Java-based.
00:15:35.530 The focus on managing memory usage effectively is a defining characteristic of JRuby, allowing users to handle high traffic volumes by leveraging enhanced threading features.
00:16:02.240 These performance benchmarks on a simple scaffolded Rails application at the full-stack level demonstrate the ongoing challenges we face and the steps removed from CRuby.
00:16:36.320 However, recent optimizations over the past year show that JRuby is now convincingly viable for real-world Rails applications.
00:17:05.540 Some recent tests revealed that the JRuby performance is approaching optimal ranges for simple applications, structured around the active record and related to database overhead.
00:17:43.150 Acknowledging the importance of optimization, we aim to ensure that JRuby runs successfully with a stable structure, which will positively influence long term solutions.
00:18:19.230 As we work on performance, understanding how various external benchmarks and associated tools impact overall performance is vital. Each benchmarking process introduces its own quirks, especially regarding concurrent requests.
00:18:57.420 Issues related to connection management, particularly in how tools handle HTTP connections in relation to place a significant mark on overall benchmarks.
00:19:26.040 Using different benchmarking tools yields varied findings and allows for critical assessments in testing configurations.
00:19:55.100 To underscore the importance of detailed testing, issues with keep-alive functions were explored that showed inconsistencies in behavior through different modules.
00:20:23.050 In summary, the evaluation of JRuby remains ongoing with active efforts to ensure it remains a competitive solution for Rails applications moving forward.
00:20:52.280 We also dealt with some key intricacies associated with resident memory, particularly with JRuby just requiring a fraction of the memory needed in equivalent CRuby setups.
00:21:23.640 This innovation paves the way for looking into additional production complexities that arise in full deployments.
00:21:54.050 Having the opportunity to benchmark JRuby against larger applications offers insights for other developers considering JRuby for their own projects.
00:22:22.950 This discussion leads to important considerations on strategies that can improve JRuby deployments.
00:22:55.340 Integration with larger applications, such as RubyGems.org, faced its share of challenges in effectively folding into production.
00:23:23.270 However, incorporating foundational tools and configuring benchmarking appropriately allows for clearer assessments of JRuby, helping trace its ongoing viability.
00:24:03.950 As we near the end of our benchmark presentation, the focus shifts towards how JRuby manages Rails applications to ensure efficient method calls. Understanding the implications of memory usage contributes significantly to developments moving ahead.
00:24:43.530 The final chapter outlines the critical need for careful management of systems to avoid common pitfalls that can negatively influence performance.
00:25:34.760 We delve into the different approaches existing for users who wish to move from C Ruby to JRuby, including the installation of the JRuby lint gem.
00:26:21.240 This analysis will yield comprehensive reports for users highlighting incompatibilities present in their code or gems.
00:26:54.550 Going through the report allows developers to identify problematic gems and how they might need to adapt.
00:27:29.830 Ultimately, common strategies can provide routes to address notable challenges, enhancing JRuby compatibility.
00:28:07.660 The trending focus remains on gradual migration to JRuby, ensuring new developments remain integrated effectively within the larger Ruby community.
00:28:46.880 So, as you pursue any migration, keep in mind that adding platform tags, writing pure Ruby, utilizing FFI libraries, or developing Java native extensions will significantly enhance processes and interactions.
00:29:31.240 The aim is for Ruby developers to embrace JRuby through seamless adaptation and community engagement.
00:30:16.840 As we approach the conclusion of this discussion, we emphasize the uptake of JRuby across various gems as community efforts yield good progress.
00:30:54.220 The ongoing work conducted by contributors will remain on full display as we encourage other developers to equally explore this rich landscape.
00:31:23.690 To conclude, addressing scales of practical use with JRuby against Rails enables developers to keep a watchful eye for best practices that could enhance performance within their own applications.
00:32:15.640 I want to thank everyone for joining this presentation. We'll open up for questions to better understand any particular aspects you might want to discuss further.