Charles Nutter

Closing Keynote: Scalable Applications with JRuby

Scalable Applications with JRuby by Charles Nutter.mp4

I work on JRuby, the fastest and most scalable way to run Ruby web applications. This past year we’ve continued work on better database support, more Ruby optimizations, and tighter integration with recent JDK releases. This talk will show how to get started with JRuby.

JRuby is the fastest and most scalable way to run web applications built with Ruby or Rails. This past year we’ve continued work on better database support, more Ruby optimizations, and tighter integration with recent JDK releases. In this talk, I’ll cover:

Getting started with JRuby, building new applications or migrating existing ones.
Things to know about scaling JRuby, including tuning flags and deployment patterns.
Future plans for maintaining Ruby and Rails compatibility.
A call-to-action for anyone who’d like to help keep JRuby moving forward.

RubyConf TH 2019

00:00:07.450 Hello everyone, nice to see all of you! This is my first time here, and I’m very excited. I have a lot to share.
00:00:14.690 I have been a Java JVM developer for pretty much my whole career, about 24 to 25 years now. Amazingly, I have spent about 13 years working full-time on a Ruby implementation, which has been very exciting. We are thrilled to have the sponsorship of Red Hat.
00:00:34.309 As I mentioned, this is my first time here, and I plan to spend a few days exploring Chiang Mai afterwards. Thank you again, Red Hat, for sponsoring us.
00:00:42.260 We’ve had some great sponsors in the past that have kept the project going. We started out at Sun Microsystems, had a stint at Engine Yard, and now for over six years, we have been at Red Hat, where they are funding two of us to work full-time on JRuby. We're also looking forward to collaborating with IBM, which may provide additional resources to make JRuby really shine.
00:01:17.810 Now, let's get into it. How many folks here are familiar with JRuby? About a third of the room. And how many of you have ever deployed a JRuby application in production? Great, it seems like around a fifth or a sixth of the room.
00:01:30.500 For those not familiar with JRuby, it is a Ruby implementation with the primary goal of being as much of a drop-in replacement for Ruby as possible. The current version is compatible with Ruby 2.5, and we are looking to support Ruby 2.6 or 2.7 for the next major JRuby release.
00:01:49.310 If you encounter anything that isn't working, don’t assume it’s your fault. Let us know! There’s a very good chance we have missed a weird edge case that we can fix quickly. Most pure Ruby gems should work just fine with JRuby. We ship a slightly modified version of CRuby’s pure Ruby standard library, and most major C extensions and native libraries have JRuby versions or equivalent libraries that will work well.
00:02:08.629 We prioritize being a Ruby implementation first, and secondly, being a JVM language. This allows us to leverage all of the power and capabilities that the Java platform provides.
00:02:33.080 In the past couple of days, I saw a tweet from a user named Michelle on Twitter. She has two kitties named Java and Ruby, and they play together happily. It makes me think, if they had a kitten together, it would definitely be JRuby! This sums up our goal—JRuby as a synergy of Java and Ruby, working together.
00:02:44.540 What are some benefits of using the JVM? First of all, it’s widely deployed and available on every platform. You also get amazing native JIT capabilities for performance, and garbage collection is never a problem. There are numerous garbage collectors available on the JVM which are highly efficient. The concurrency support across various platforms is also robust—"write once, run anywhere" holds true for us. We already have users deploying JRuby on exotic platforms without needing to modify their apps.
00:03:25.730 I want to highlight an example from my personal experience. With one JRuby process, I can utilize all cores of my machine efficiently without having to spin up multiple processes. This is a crucial advantage—ample CPU and resource use with just a single JRuby instance. I also use a tool called Visual VM, which provides insights into the JVM's garbage collector and resource usage.
00:03:56.500 We also have more than 150,000 unique gems in the Ruby ecosystem that you can leverage. In addition, there are over 340,000 JVM libraries available that can cater to almost every imaginable need. If you can’t find a library in the Ruby world, it’s likely that there’s a JVM library that you can seamlessly integrate into JRuby.
00:04:50.720 One fun example I came across is a Minecraft plugin framework written in JRuby. The code might seem trivial, but a colleague of mine, Tom, tested it and ended up creating several hundred thousand chickens in his game world. Naturally, he had to abandon that world because chaos ensued! This showcases how much fun you can have with JRuby while leveraging the power of the JVM.
00:05:30.029 In conclusion, JRuby is Ruby, enhanced with the capability of the JVM. We strive to hide the complexities of the JVM and make it feel like a Ruby application, but with significantly more power.
00:06:14.310 Let me provide you a quick roadmap for JRuby. The current JRuby version is compatible with Ruby 2.5. We have completed the 9.1 line, which was aligned with Ruby 2.3, but we are likely to skip over Ruby 2.6. Maintaining compatibility is a significant effort for us. We prefer to focus on compatibility for a few months before transitioning to user support and performance optimizations. Therefore, we will wait until Ruby 2.7 is done by the end of this year, and we'll plan to release JRuby 9.3 next spring with Ruby 2.7 compatibility.
00:07:14.690 This is a great opportunity for anyone who is eager to assist. As new Ruby features come out, we are always looking for folks to help implement them in JRuby. You’re welcome to submit Ruby code for any new feature. Large segments of JRuby are actually written in Ruby itself, which means that you can submit changes in Ruby, and we can optimize them later if necessary.
00:08:34.540 So, if you’re a Ruby user wondering how to get started with JRuby, we do have a website that provides downloads, community information, chat links, and further guidance. The only requirement for getting JRuby running is to have a JDK installed. My personal favorite is Adopt OpenJDK, as they provide builds across various platforms with different JVM configurations. Currently, we recommend using Java 8 because Java 9 or higher includes security and module configurations that can generate warnings with some JRuby applications, although it’s harmless.
00:09:43.190 To install JRuby, you can simply download the tarball or zip file or use our Windows installer. If you’re a Windows user, just tell your preferred Ruby installer to install JRuby, as they all know about it. You’ll have JRuby up and running in no time.
00:10:24.360 Let’s take a quick look at running JRuby and IRB (Interactive Ruby). Of course, in the Java world, everything begins with a 'J'—we use JIRB. You can also run IRB directly, but JIRB is simply a convenient shortcut. I’ll show you how to interact with Java libraries using JRuby, such as creating a GUI application with the Java Swing toolkit.
00:11:04.480 In this example, we create a frame and a button, set their sizes for visibility, and show the frame. With similar concepts, you can add event handling to our buttons, and when clicked, your Ruby code executes. You can also explore the JavaFX framework, which is supported by JRuby, providing a modern toolkit for building JVM-based desktop applications. This makes it easier than figuring out the right GUI libraries across different platforms.
00:12:03.400 Regarding gems and paths, it's important to be mindful that sometimes system installers for Ruby might attempt to share gem paths. This can lead to confusion since different versions of some libraries exist for JRuby. Additionally, many projects and libraries use the .ruby-version file to switch to a particular Ruby version, often silently. It’s easy to end up back in CRuby instead of JRuby without realizing it.
00:13:03.250 I want to stress that we're always available to help. We have a mailing list and are on various chat services, making it easy to reach out. Additionally, you can always find us on GitHub in the JRuby organization.
00:13:42.039 Now, let’s delve into JRuby's architecture. We have what we call a tiered architecture, comprising several layers of execution and optimization. Our Ruby code is parsed and compiled into internal Ruby instructions, similar to CRuby's VM and bytecode.
00:14:01.880 Then, we hand that off to our interpreter, which is written in Java. This interpreter runs the code for a while, and as it detects that certain methods are being used often, we pass that off to the JVM as JVM bytecode via our own JIT phase. This transition allows the JVM to optimize further, generating native code that ultimately improves performance. The cycle keeps going, meaning the longer you run your Ruby code on JRuby, the better its performance will be—this is reflected in the benchmarks I will show.
00:15:40.719 A key responsibility I hold at JRuby is memory and performance optimization. I work with the JIT and backend optimization that connects with the JVM. My analysis often includes reviewing assembly code to enhance performance, enabling you to benefit from this behind-the-scenes work.
00:16:40.380 I’d like to share some micro-benchmarks, which, though not particularly applicable to everyone, help us explore low-level performance aspects of JRuby. These benchmarks allow us to test numeric performance, crucial when evaluating the JVM's capabilities with Ruby code.
00:17:30.450 One illustrative benchmark generates a fractal, which puts a lot of strain on floating-point math, pushing the JVM to produce optimized native code. The results of this benchmark, showcasing various Ruby configurations, provide a glimpse of JRuby’s potential.
00:18:28.750 In observing the performance of these configurations, we note that CRuby 2.5 runs this benchmark in about 3.6 seconds. JRuby, when executed in an ordinary manner without the invokedynamic flag, shows potential for improvement, but we're not quite there yet.
00:19:18.340 Turning on invokedynamic, which we added alongside various other features of the JVM, significantly boosts performance. This optimization has continuously improved over time, leading to better performance, reduced optimization time, and diminished memory usage. Currently, in JRuby, this is an opt-in feature, meaning you can specify a flag to leverage its advantages.
00:20:10.090 This exemplifies how we have achieved impressive performance improvements, sometimes as high as five times faster, depending on the code being executed. We’ve also been excited about the emergence of new JVMs and JIT compilers, like IBM's Open J9, which we are experimenting with.
00:21:12.390 One JIT compiler to watch is Graal, which is written entirely in Java, allowing for quick evolution and integration of advanced optimizations. We are seeing amazing performance improvements on Ruby code thanks to these advancements.
00:22:04.050 Thus far, we’ve compared C Ruby 2.6’s JIT performance with JRuby utilizing invoke dynamic, and it typically shows significant performance bumps.
00:22:58.220 As we apply newer JIT technologies, we can experience drastic performance improvements, making JRuby performances very close to Java execution. It’s thrilling to note that with the right configurations, JRuby's performance can rival that of code written directly in Java.
00:23:36.430 On memory optimization, we're constantly searching for ways to keep JRuby applications lean. JVM applications can consume considerable memory due to the tendency of creating too many objects. We aim to keep Ruby in JRuby as compact and tight as possible.
00:24:05.610 For instance, Ruby instance variables are dynamic; however, we can often predict their configurations. Our focus is primarily on converting instance variables into JVM fields, significantly reducing memory overhead.
00:24:41.550 Additionally, we employ array optimizations, aiming for improved memory utilization for small arrays, effectively turning many instances into corresponding JVM fields. This strategy keeps it compact and close to CPU caches, reducing unnecessary overhead.
00:25:32.820 Our recent implementations have led to a 33% reduction in memory usage, which various applications are now benefiting from. It’s crucial to keep in mind the warm-up times entailed in the tiered execution process.
00:26:22.470 We continuously work to mitigate startup impacts, yet warm-up time also affects performance. Typical results showcase that JRuby can be slower than CRuby at startup, especially when processing more gems.
00:27:12.140 However, warm-up time has been decreasing with every release, and any performance benefits surely outweigh the drawbacks. We suggest using the –dev flag in a development environment, which results in significant reductions in JRuby's startup time.
00:27:30.120 In looking at how JRuby interacts with web applications and performance scales, we can see significant improvements. I want to shift towards benchmarks and demonstrate a few key examples using Sinatra and Rhoda, which are notably efficient with JRuby.
00:28:24.740 We also see distinct performance advantages with JRuby in these web frameworks, showcasing its capability to process various requests more effectively than CRuby.
00:29:17.700 Our testing reveals that JRuby effectively acknowledges a larger request volume, sharply upticking performance by almost four times in some instances. We maintain numerous production users leveraging JRuby for large-scale applications.
00:30:09.590 It’s worth noting that one specific sizeable consulting firm in Asia successfully implemented a JRuby Sinatra application, handling a massive number of requests across their platform. As some benchmarks will suggest, JRuby shows promise when scrutinized against CRuby.
00:30:52.850 We’ve recorded metrics where in C Ruby, Sinatra achieves around 12,000 requests per second compared to JRuby's impressive upward shift to approximately 44,000 requests. This is indicative of the optimizations present within JRuby to deliver substantial performance gains.
00:31:54.210 As we transition into discussing JRuby on Rails, I want to highlight multiple success stories. For instance, a single multi-threaded Rails process can adeptly manage an entire application, evolving drastically from the traditional need for separate CRuby processes.
00:32:56.890 With Rails 6.39 results, there's clear evidence of our pursuit of performance enhancement. The adjustments necessary for users transitioning over to JRuby from CRuby are pretty minimal in terms of configuration changes.
00:34:11.070 We’ve been optimizing ActiveRecord because most Rails applications rely on this component heavily. So our benchmarks reveal an impressive 30% performance improvement with throughput and memory utilization compared to running ActiveRecord in CRuby.
00:35:25.800 Similarly, we’ve observed the same performance pattern across backend operations, such as creating and updating records. Running these benchmarks consistently highlights the advantages of using JRuby over CRuby.
00:36:25.390 It’s essential to mention that JRuby can perform even better under heavy loads compared to multiple CRuby processes with its scaling advantage stemming from many threads managed within a single actor.
00:37:20.020 To give you some context, the performance metrics while running RubyGems.org exemplify JRuby's ability to sustain high concurrency, executing commands and requests effectively without experiencing failure compared to CRuby.
00:38:20.830 In wrapping things up, I encourage everyone to give JRuby a try. While migrating existing applications will be more laborious, new applications that leverage JRuby can significantly benefit from its performance and scalability.
00:39:25.370 The discourse around transitioning from CRuby to JRuby often highlights frictions associated with C extensions or libraries without JRuby equivalents. However, it is possible to effectively navigate and replace these components with JVM libraries, which typically produces less overhead in JRuby.
00:40:48.280 Overall, JRuby has proven to be beneficial for applications, and I am always available to assist anyone interested in further extending Ruby's capabilities through JRuby, combining it with the power of the JVM.
00:41:59.110 Let's keep the Ruby dream alive, and thank you all for your time!
00:42:26.750 Thank you! We have a few minutes for questions.
00:42:33.550 One question I received is about large or well-known production applications using JRuby. For example, SoundCloud utilizes JRuby for a significant portion of its operations.
00:42:56.780 Another interesting case is the BBC News website, where all election result displays are powered by a JRuby application.
00:43:12.709 We also have the Allen Telescope Array, part of the SETI project, which uses JRuby to coordinate its functionality.
00:43:38.940 In summary, teams migrating from CRuby to JRuby often encounter start-up time issues and the lack of JRuby equivalents for certain C extensions—but we are continually working to improve these challenges.