Let me introduce you to the Advanced Ruby cartridge, which I have been working on for the past few months. In this post, I will cover what this cartridge is capable of, why being able to use different webservers rather than the default one matters, how JRuby can be beneficial, and lastly, provide some charts with speed comparison of each webserver including running on JRuby. At the end of this article you can find handy step-by-step tutorials for some typical use cases.
By default, the Ruby cartridge supports only one webserver, Passenger, running inside Apache. Currently there is no way (without a lot of hacking) to run a different webserver for Ruby applications. Such an approach has many disadvantages and that is why I created a proof of concept Advanced Ruby cartridge supporting many popular webservers and with the ability to even change your Ruby platform to JRuby. The cartridge is available on GitHub and is installed as a downloadable cartridge like this:
rhc app create YOUR_APP_NAME http://cartreflect-claytondev.rhcloud.com/reflect?github=openshift-cartridges/advanced-ruby-cartridge
The Advanced Ruby cartridge has added support for many popular webservers, specifically: puma, unicorn, thin and the default passenger. If your favorite one is missing, you can easily extend it by adding a special action hook called
server_control. More information is in the README on Github.
Switching webservers is done by editing the OpenShift user environment variable
OPENSHIFT_RUBY_SERVER through the rhc client. Allowed keywords are
passenger, puma, unicorn, thin and custom <code>. For example, for puma, the command would look like: <code> rhc env set OPENSHIFT_RUBY_SERVER=puma -a YOUR_APP_NAME
Then you need to restart your app to take effect.
rhc app restart YOUR_APP_NAME
Note the default server is passenger. If you are running Rails or just using Bundler, you need to add the selected server into your Gemfile, as an example for puma:
group :production do gem 'puma' end
If you are building modern application based on HTML5 you’ll often want to use WebSockets. With an official Ruby cartridge this can’t be done. Passenger with Apache does not support WebSockets and Apache wasn’t built to handle many persistent connections. Changing servers on an official Ruby cartridge requires a lot of hacking, but on the Advanced Ruby cartridge, it’s pretty easy. Webservers like thin or puma support websockets out of the box. The only thing you need to do if you are using the Advanced Ruby cartridge is to switch webservers, implement websockets support in your application, and point all websocket requests to your domain on port 8000 (e.g. appname-domain.rhcloud.com:8000). If you are using Rails, I recommend using the websocket-rails gem, which makes implementation pretty easy. For Sinatra, I made an example websockets application which works pretty well on puma, thin, and unicorn (even though unicorn is not a good option for websockets, its major purpose is to serve fast clients) .
JRuby can be really useful in production environments, especially for enterprise products. The stability of JVM and a tight connection with Java can be beneficial. Keep in mind that JRuby needs some warm up time in order to catch up with the default MRI.
Unfortunately, not all webservers run on JRuby because JRuby doesn’t support C extensions. Right now from the provided ones only puma has support for JRuby, though I may add other in the future. The deployment process of your app using JRuby can be slower compared to MRI, especially if it is a more complex Rails application.
Switching to JRuby is possible by editing the OPENSHIFT_RUBY_PLATFORM variable and setting it like this:
rhc env set OPENSHIFT_RUBY_PLATFORM=jruby -a APP_NAME
Push your new code so it takes effect (JRuby must install needed gems, that’s why restart is not enough).
Webserver speed tests were performed on OpenShift Online using the ApacheBench tool. I used a test application written in Rails using a MySQL database on a set of small gears. Warm up of each server consisted of (1000 * n) requests with (10 * n) concurrency, where n is equal to the number of used gears. All requests were sent from separate virtual servers on Amazon EC2 for minimal latency time and maximum throughput.
Results for non-scaled applications (just 1 gear, MySQL and web application on the same gear):
Results for scaled applications using 10 gears, 1 gear for MySQL, 1 gear for HAProxy and the other gears for processing requests on web applications:
Summary of the results: the performance of JRuby is really impressive, puma on JRuby has results similar to passenger on MRI. Passenger didn’t perform as well as unicorn and puma running on MRI.
One more thing I noticed was using medium or larger gears for Ruby applications had no effect on webserver performance. The bottleneck during performance testing was from cpu limitations, not the amount of RAM. This will vary for different applications. To check your RAM usage for each gear:
rhc ssh APP_NAME --gears "ps aux"
To help you to get started with this cartridge, let’s take a look at some simple use-cases that might help you. This should give you some idea what the theory mentioned above looks like in practice.
Case 1: I want to upload my JRuby application and run it on OpenShift.
You already have a JRuby based application and you want to deploy it to OpenShift.
rhc app create YOUR_APP_NAME http://git.io/Nl3akg rhc env set OPENSHIFT_RUBY_PLATFORM=jruby -a APP_NAME rhc env set OPENSHIFT_RUBY_SERVER=puma -a APP_NAME cd into-your-application/ # the git url is given after creating application ( rhc app create … ), or you can get it by running rhc apps git remote add openshift GIT_URL git push openshift +master # wait until the deployment process is finished and then you can access your JRuby application
Case 2: I want to use WebSockets in my Ruby application on OpenShift.
You do have an application using WebSockets and you want to deploy it to OpenShift.
rhc app create YOUR_APP_NAME http://git.io/Nl3akg # use puma or thin, I personally prefer puma rhc env set OPENSHIFT_RUBY_SERVER=puma -a APP_NAME cd into-your-application/ # git url is given after creating application ( rhc app create … ), or you can get it by running rhc apps git remote add openshift GIT_URL git push openshift +master # wait until the deployment process is finished and then you can access your JRuby application
OpenShift already has solid support for Ruby. With our new Advanced Ruby cartridge you can get exceptional support for your Ruby needs. One important thing to mention–this cartridge is community maintained and OpenShift does not provide support for it. If you decide to use it, naturally we provide the environment, but if the cartridge itself becomes problematic, the OpenShift support team may only be of limited assistance. We’re always on IRC #openshift on irc.freenode.net and also have an active presence on StackOverflow.