JRuby

Using JRuby: What, When, How, and Why

Using JRuby: What, When, How, and Why

by Charles Nutter

In the video "Using JRuby: What, When, How, and Why", Charles Nutter discusses JRuby, a Ruby implementation on the Java Virtual Machine (JVM), emphasizing its compatibility with Ruby 3.1 and the advantages of using JRuby for developers. Throughout the presentation, he covers the following key points:

  • Introduction to JRuby:

    JRuby is designed primarily as a Ruby implementation with the added benefits of the JVM. It allows Ruby developers to run Ruby applications while leveraging JVM features.

  • Benefits of JRuby:

    • Concurrency: JRuby supports true parallel threading, allowing better utilization of CPU resources without needing multiple workers.
    • Ruby Compatibility: The recent JRuby 9.4 version enhances compatibility, jumping from Ruby 2.6 to Ruby 3.1. While some features remain unsupported, the focus is on maintaining Ruby's essence.
    • Access to JVM Libraries: Developers can easily integrate Java libraries into Ruby applications, leading to a rich ecosystem of tools for debugging and monitoring.
  • Getting Started with JRuby:

    Installation is straightforward, requiring a Java JDK. Developers can find resources at jruby.org and can use various installation tools. Core libraries from Java can be accessed similarly to Ruby classes.

  • Use Cases and Performance Insights:

    • Nutter mentions notable historical uses of JRuby by organizations like the BBC and NASA. He notes the importance of performance benchmarking, highlighting that JRuby can outperform other Ruby implementations under specific conditions, particularly in high concurrency scenarios.
    • The benchmarking results indicate that, although JRuby may have higher memory consumption initially, it can achieve better performance as systems warm up, often outpacing C Ruby under load.
  • Integrating with Database Systems:

    JRuby supports Ruby on Rails effectively and has been optimized for SQLite and MySQL databases. A transition to JRuby might require minor adjustments in application configuration depending on the gems and database setup.

  • Future Directions:

    JRuby’s team plans continued optimizations and stays engaged with upcoming technologies in the JVM landscape, including benchmarking improvements.

  • Final Thoughts:

    By choosing JRuby, developers can benefit from enhanced performance, better resource management, and a more robust ecosystem, especially in situations where scaling is crucial. Nutter encourages attendees to explore JRuby further and engage with the community to address any issues or contribute to the project.

00:00:00.000 Ready for takeoff.
00:00:16.940 All right, we're going to get started. I have a lot of material to cover. I am Charles Nutter, and I will be speaking about the project I've been working on for the past 16 years: JRuby.
00:00:24.000 I want to give you a little idea of what JRuby is, why it's useful, and how you might get started using it. First of all, I want to thank Yarden Leifenfeld, who could not be here. She was originally set to give a JRuby talk during this slot, but she had other commitments.
00:00:37.140 If you check it out, there are videos online of her talk "Ruby and JVM: A Love Story," where she provides a detailed exploration of how her company has been using JRuby, including building a debugger based on the JVM debugger. There is a lot of cool content, so I encourage you to check that out.
00:00:51.539 I apologize to Yarden, but I was not able to include any of her content since 30 minutes is not long enough. Also, I want to express my thanks to Red Hat and IBM. I am an employee at Red Hat, and they have sponsored our work on JRuby for over 10 years, which allows us to work on JRuby full time.
00:01:10.500 Don't ask why they are so generous with open-source projects. Just buy Red Hat. And of course, cheers to Tom Annabelle, who is still isolating at home, worried about COVID-19. We've been co-leading JRuby for these past 16 years and have traveled a lot, enjoying some beer along the way.
00:01:21.600 He's the silent partner who does a lot of the real work on JRuby behind the scenes.
00:01:39.659 All right, let's get into it. So, what is JRuby? It's not surprising that JRuby is a Ruby on top of the JVM. How many folks here are somewhat familiar with JRuby? Okay, and how many have actually run something on JRuby? Pretty much the same folks.
00:01:51.720 JRuby is a Ruby implementation that emphasizes being a Ruby implementation first and a JVM language second. There are many people on the Java side who enjoy using JRuby to script Java applications, but our primary focus is on the Ruby developer experience. Once you install JRuby, you can run all the same commands from the command line, just like with MRI Ruby. You get all the benefits that come from being on the JVM.
00:02:27.780 The general idea is that Ruby code should just work. You should be able to take any pure Ruby application and many of the extensions that have JRuby versions, plug your application into JRuby, and it should run out of the box. However, we don't support the C extension API that MRI Ruby does; instead, we have our own extension API, so some libraries might need to be ported.
00:02:58.560 We do not support forking because the JVM doesn't support it. Moreover, unlike MRI Ruby, our threads run in parallel, meaning one process can saturate your entire CPU. You don't need to run multiple workers.
00:03:30.000 I've been using this slide for years. Some of the companies listed may no longer use JRuby, but they all did at one point. For example, the BBC has used JRuby to deliver election results, such as the results from the last Scottish referendum on independence.
00:03:44.000 Additionally, I know that JRuby was once used at NASA to script components for one of their SETI projects searching for extraterrestrial life. Exciting stuff!
00:04:03.540 JRuby is indeed a Ruby implementation, and let's discuss Ruby compatibility. Just last week, we managed to release JRuby 9.4. This version jumps from Ruby 2.6 compatibility all the way up to Ruby 3.1, and most of the features in these versions have been implemented.
00:04:17.760 Some notable exceptions are that we do not yet support the Fiber I/O scheduling API and we do not support Reactors, but I am not sure if many people are using those features anyway. We will continue to maintain JRuby 9.3 for the next year or so based on demand.
00:04:42.540 We have a strong focus on compatibility before performance; JRuby 9.4 has had almost no performance tuning during its development. Nevertheless, it still runs very well, and as I will show you later, we expect to see significant improvements now that we are back on track with compatibility.
00:05:08.040 So, why is running Ruby on the JVM interesting? Well, the JVM is ubiquitous; every platform out there has a JVM available. Moreover, most of these are well-supported by companies like Oracle and Red Hat.
00:05:21.000 We also have access to excellent JIT compilers, various garbage collectors with a wide range of tuning options, and great concurrency support right out of the box. Additionally, since we're running on the JVM, we can access all of the libraries available on this platform, whether they are written in Java, Scala, Closure, or any other language.
00:05:51.300 You can import those libraries directly into your Ruby code and call them like any Ruby library. There's also a plethora of tools available with the JVM for monitoring, production monitoring, debugging, profiling, and all that functionality works almost seamlessly with JRuby.
00:06:09.539 Furthermore, because we run on the JVM, your Ruby application can operate on a variety of different and exotic platforms. We were among the first alternative Ruby implementations to have support for Apple's M1, and we also run on older systems like OS/400 and AIX.
00:06:32.340 If you have any legacy application servers you want to transition to Ruby, JRuby provides that flexibility.
00:06:57.900 This slide shows one of the tools we've showcased for years: VisualVM. The right side displays the Visual GC plugin, which provides a live view of the garbage collector heaps, allowing you to see how generations fill up and objects get promoted.
00:07:07.740 You can monitor this via JRuby in production and gather this insight without additional costs.
00:07:13.860 As I mentioned earlier, JRuby can efficiently utilize all CPU cores in your system, so you do not need to manage multiple workers, thereby minimizing memory usage. One process with multiple threads can handle the workload across your entire system.
00:07:30.000 In terms of integration with Java, we have exciting projects, such as the Progen framework, which is a bucket-based plugin for using Ruby to write Minecraft mods. An example is a simple modification to increase the number of chickens that spawn from an egg. Tom Moore did most of the work on this, and there's a fun backstory of him accidentally creating too many chickens.
00:07:55.680 Getting started with JRuby is straightforward; you can check out jruby.org for a wealth of information. The process generally requires that you have a Java JDK installed on your system, which is pretty standard across all Linux distributions and relatively simple to install on Windows and Mac OS.
00:08:13.440 We recommend using Java 11 or higher. We support all versions of Java from 8 and higher, but we will probably drop support for Java 8 and maybe 11 in our next major release.
00:08:37.500 However, for the 9.4 cycle, we will continue to support Java 8. Installing JRuby can be done through Ruby installers like RVM or rbenv, or you can download a tarball or zip file. There is also a Windows installer, as well as a Docker image that we maintain.
00:09:01.320 The only real requirement is having a JDK available. After installation, give it a shot! For instance, here’s how you can switch to JRuby using RVM, and I’ll demonstrate calling some of the Java core libraries.
00:09:19.140 Java Lang runtime can provide information like the number of available processors and free memory. Any JVM library can be treated just like a Ruby class.
00:09:39.840 The biggest use case for Ruby developers using JRuby is JRuby on Rails, which works quite effectively. There are numerous JRuby on Rails applications in production; it’s hard to quantify exactly how many, but it could range from hundreds to thousands.
00:09:54.840 When you can get your application running on JRuby, ensure your tests pass and performance is satisfactory. You can actually run your entire system with just one JRuby instance, avoiding the need to spin up multiple workers.
00:10:12.660 Transitioning an existing application typically requires small configuration adjustments. A few gems might not be supported. For instance, if you're using MiniRacer, which is based on V8, we offer a different JavaScript implementation using either Rhino or Nashorn.
00:10:39.000 When it comes to databases, you would want to specify a host and port for MySQL since we do not support Unix sockets. Adjust the configurations so you can utilize more threads and workers.
00:10:56.760 I am pleased to announce that Rails 7 is working well on JRuby, and I will be using it for some benchmarks later. The main task when supporting a new version of Rails is to incorporate any changes to Active Record.
00:11:16.100 Right now, SQLite is performing well, MySQL works but requires attention, and we are just starting to work with PostgreSQL. In the coming weeks, we will have updates for all three databases.
00:11:36.100 Our Active Record JDBC adapter follows version matching rules; for example, the Rails 6.x versions are supported by our 6.0 Active Record JDBC adapter, and Rails 7 will be using 7.0.
00:11:44.700 As of this morning, SQLite and MySQL adapters for Rails 7 have been released, allowing quick application setup.
00:12:01.200 When it comes to performance, this factor is probably among the key reasons one would try JRuby on Rails. However, performance evaluation is tricky: you should consider what matters to you.
00:12:15.880 Are you focused on straight-line heavy data processing? Is your goal to achieve high concurrency and handle numerous users without spinning up more instances? When it comes to command-line applications, consider whether startup time matters.
00:12:43.340 C Ruby has been optimized for startup for many years. It is difficult for us to compete with that, though we continue to work on improving warm-up time.
00:13:02.540 Consider whether you need an application to reach Peak Performance immediately or if it is acceptable for the application to warm-up gradually.
00:13:24.240 Memory size might be a concern if you're consuming too much memory with multiple workers.
00:13:43.240 Benchmarking is situational and specific. What performs well for a micro-benchmark may not hold in a real-world application. Straight-line performance can be promising, but concurrency can expose weaknesses, especially under heavy loads and memory management.
00:14:22.799 Trust your benchmarks over external claims; therefore, run your own tests with your applications to ascertain their real-world performance.
00:14:39.960 For this talk, I’ll present three benchmark examples: a simple Rails benchmark, an end-to-end blog application running on MySQL, and performance insights regarding Active Record.
00:15:00.480 The Rails benchmark focuses on measuring the overhead of the Rails framework itself. It does not utilize any web server or make socket connections. It executes a single SQLite blog application script as fast as possible.
00:15:17.340 While it’s great for identifying performance bottlenecks within Rails, it might not fully represent a complete application. Therefore, I’ll also run an end-to-end benchmark for a small blog application.
00:15:39.000 As for the Rails bench results collected on my system, I was impressed to find that YJIT is performing admirably. Getting good JIT implementations in C Ruby has been slow, but YJIT is demonstrating substantial promise.
00:15:56.640 Truffle Ruby's performance numbers are reportedly better than what I experienced, so I encourage you to test this out on your own systems.
00:16:14.500 The results show that JRuby is much faster than YJIT right now, especially while we have not engaged in aggressive performance optimization over the last year or two. We expect to significantly boost performance soon.
00:16:34.559 However, benchmarks only reveal straight-line performance. They don't inform you about how concurrency affects overall performance, startup times, or their effect on memory consumption.
00:17:09.960 The memory footprint can be challenging for JVM and similar modern runtimes, as they typically consume more memory than simpler implementations.
00:17:37.800 These complex runtimes require additional memory to allow for efficient garbage collection. They may also need to maintain multiple code copies, further straining memory usage.
00:18:09.780 We face challenges competing with C Ruby, which has focused on optimizing startup time and memory usage over the years. Hence, it’s crucial to look beyond raw performance numbers.
00:18:31.740 Launching a Rails bench example, C Ruby 3.1 consumes about 80-90 MB of memory on my system, while JRuby and Truffle Ruby are significantly more demanding.
00:19:00.420 These numbers can vary based on JVM tuning. The JVM tends to allocate more memory to give its garbage collector room to operate effectively.
00:19:23.520 In practice, this benchmark could run with a smaller JVM heap, but with some tuning, I figured I could make the benchmark run in a reduced footprint.
00:19:43.800 With a minimized heap allocation, I managed to run with JRuby utilizing only about 950 MB of memory, thereby helping lower production costs.
00:20:05.640 Regarding warm-up times, similar trends apply as are observed in the Rails benchmark, where JRuby must initially interpret many components, leading to potentially slower performance.
00:20:31.800 It is important to remember that the Java string implementation and the list implementations start cold and require time to JIT and warm up.
00:20:50.100 Garbage collection mechanisms may also influence how the heap size adjusts as performance stabilizes. We're consistently focused on improving our warm-up time.
00:21:06.800 This graph depicts performance iterations over time for the Rails benchmark across C Ruby and JRuby. While C Ruby stabilized relatively quickly, JRuby took several iterations to reach a steady performance level.
00:21:38.640 When deploying JRuby in production, you may notice that initial requests start slower and gradually improve as the application warms up.
00:21:55.680 Conversely, some developers deploy scripts to warm up their applications post-deployment.
00:22:21.000 Comparing graphs from the performance of C Ruby versus JRuby involved layering them; JRuby tends to outperform C Ruby around the sixth iteration.
00:22:44.180 Truffle Ruby takes longer to stabilize performance and even lags further behind in terms of iterations near my run timings. It will eventually stabilize, but often it requires more attention.
00:23:10.680 These observations underline the importance of real-world checks because many of these figures are situational and specific to each application.
00:23:29.520 Now, let’s transition into more realistic benchmarks involving end-to-end scenarios.
00:23:43.680 I’m running a relatively simple blog application on MySQL hosted on my local Linux system. I deployed C Ruby 3.1 with 16 workers, each with two threads, to ensure optimal CPU usage.
00:24:12.720 The JRuby setup utilized 32 threads in a single process, though I encountered issues using Truffle Ruby which will be discussed briefly.
00:24:31.440 In this scenario, C Ruby achieved around 2000 requests per second, while YJIT performed slightly better with 2361 requests per second.
00:24:53.700 However, when heavily loaded with concurrency, JRuby showed twice the performance of C Ruby with YJIT.
00:25:09.180 When concerning memory footprints, C Ruby averaged around 1.5 GB for 16 instances using Puma.
00:25:27.440 Meanwhile, applications using JRuby operated around 1.4 GB, indicating that JRuby can outdo C Ruby when carefully configured.
00:25:44.180 Once configured correctly, JRuby’s memory footprint aligns more favorably with needs observed in production environments.
00:26:07.560 Performance optimizations in Active Record are an ongoing effort. The complexity inherent in Active Record has posed challenges, but we continue to refine our adapter while JRuby evolves.
00:26:29.040 The improvements seen moving from Java 11 to Java 17 have yielded substantial performance benefits across various benchmarks.
00:26:48.720 When performing select benchmarks during tests, I've observed that JRuby frequently outperformed C Ruby, highlighting the need for extensive situational checks.
00:27:02.480 It’s essential to employ real-world benchmarks tailored for your application to confirm achievable performance gains.
00:27:16.440 For instance, many years ago, a large Rails application running on 40 extra-large EC2 instances was faced with hefty costs. By migrating to JRuby, they managed to bring this down to only 10 instances.
00:27:45.840 They were able to significantly cut AWS costs, achieving better throughput with lower per-request response times.
00:28:06.000 While transitioning to JRuby requires some effort, it is often worth the endeavor for your application.
00:28:31.440 And to summarize, JRuby 9.4 is out, and we've included welcome performance improvements that we hope you will explore.
00:28:54.840 Please report any issues you encounter; it may not be your fault—often, it's our problem. We encourage contributions and PRs, aiming to transfer more code into the Ruby kernel, where missing features could be fixed through Ruby alternatives.
00:29:12.840 We have plans for optimization within JRuby, as we aim to bring our performance closer to competing benchmarks. Additionally, upgrades to the JVM and explorations of new JITs and garbage collectors may enhance our functionalities.
00:29:39.420 For Rails, we have a stable future, especially with Rails 7 proving effective. As your application scales, don't hesitate to consider JRuby as a viable solution for resource optimization.
00:30:08.880 I will be available during the conference, so feel free to approach me to discuss transitioning your applications to JRuby.