How to Scale Your Ruby on Rails Application

Scaling power In our previous posts demonstrating Ruby on Rails with OpenShift applications we explored deploying SQL Rails and NoSQL Rails based applications . However, both articles demonstrated non-scalable applications. Let's take a look what happens once you want to start scaling on OpenShift.

Scalable, non-scalable ... I want to scale, always!

Do you? In case you do need to scale all the time, our platform allows you, nothing blocks you from doing that. However there are users who do not need to scale all the time, and in such cases, OpenShift allows you to keep your cost lower by changing the deployment of the the application.

Non-scalable application

In case of non-scalable applications, all the cartridges live in the same gear. In essence we create one environment for your application and then start all the cartridges in the same environment, thus all the services share the same amount of memory defined by the gear type - only small in the free tier. They also share CPU and disk resources as well. Your database and git repository will both be counting against your disk quota on the gear.

This is good for small deployments as you can run the whole stack and consume only one gear.

Scalable application

Scalable applications work a bit differently. In such a deployment you have 3 types of gears. You do have something that we call a main gear, you have application gears and cartridge gears. Your application will at the beginning also consume only one gear, however compared to non-scalable, as you add cartridges, more and more gears will be consumed. In addition, as the load coming to your application grows, and the platform will scales, your application will consume more gears.

Let's take a look at those three gear types.

Cartridge gears

Once you add a cartridge to an application it will be started in a new separate gear from the application gears. This ensures that the application and the cartridges may be scaled independently. To make it more complicated there are also three types of cartridges.

Language cartridges

These do not consume a separate gear and can not be added to an application past your initial choise. . In example when you create an application with the type ruby-1.9, you selected this kind of gear, however, you can not change nor add different web language gears, such as Python or Java to your Ruby application.

Embeddable cartridges

Embeddable gears are put into the main gear and also do not consume another gear. These are mostly very lightweight features like phpmyadmin or haproxy for which the a separate gear would be overkill and would only boost the price for our customers.

Standalone cartridges

This is a gear you usually hear about. As I like to define it "it's something your application needs alongside the application server to be functional". Usually these are database server or some other services, that your application consumes over a network connection. These consume one or more separate gears depending on the scale of the cartridge.

Scaled gears

Those are the gears where the scaled application lives. Once the scale up event is triggered, we start a new gear and rsync the content of your main gears's $OPENSHIFT_REPO_DIR over there. After that the application server is started, being it Apache or JBoss or whatever else depending on your application type. Once the scale down event is triggered, one of these scaled gears is torn down and it's resources reclaied. In that case your will not be billed for that particular gear anymore.

Main gear

Every application has exactly one main gear. It's difficult to distinguish it from the other gears, as this one plays an important and irreplaceable role in the architecture. When you push your code over git to OpenShift it goes into this gear and then the code is distributed to the other gears. In this particular gear, we also install the cartridge for the haproxy load balancer. When you add phpmyadmin or some other lightweight cartridge, it will be embedded into this gear. This gear's git repo is used during the rsync that occurs when an application scales and adds another gear.

So, we finished our small trip over the gears and cartridges, let's see what the architecture looks like.

Scalable architecture

First, let's take a look at a picture

OpenShift in a complete picture

This picture makes simplifications in the gear architecture, but nicely describes the main environment. You can see that once a request is issued for an OpenShift application, it goes through the outside routing layer based on Apache HTTPd that is capable of translating the domain name of the application into the internal address of the application itself, which is represented by the first gear.

So, what happens? The request is issued on the client side and goes through Apache proxy and hits the gear itself.

In case of non-scalable application, once the request hits the gear, it goes straight to the application. Done!

In case of scalable it's a bit more complicated. The request hits the haproxy load balancer running in the gear and that will route the request to one of the web language gears of your scaled application.

So, you have only one gear for your application? Then all the request go to the application server running in the same gear as the haproxy - i.e. main gear. Depending on the number of gears you have available for your application, the weight of the main gear in the balancer will decrease. In essence this means that with enough gears none of the HTTP requests will hit the application server in the main gear and thus the whole gear will be available for your haproxy to handle all the load that is coming to your application.

You see that haproxy plays a big role in the architecture and thus I shall deep dive into it in a separate article.

Rails & datastores

Let's talk what does this means for our Rails application. In a non-scalable application you use the environment variable to connect to the data store, and you do the same in scalable ones. You can take a look at those in one of the previous parts I linked in the beginning of this article.

In a non-scalable application the environment variable point to the same gear, in scalable they contain an address to a separate gear. For your application it's totally transparent and there is no need to change the code. All the management is handles by OpenShift.

Beware of file-system

This is the crucial point. File-systems does not scale. In case of non-scalable application it's safe to use the $OPENSHIFT_DATA_DIR to store your files, as there are no other gears that would need to an access to it.

However in case of scalable ones, it's no so simple. As I said before, only the $OPENSHIFT_REPO_DIR is rsynced, thus if you write some file into the $OPENSHIFT_DATA_DIR in one gear, it's not visible to the other gears. I believe you see the problem we face here. You have a several directories in several gears, the gears may be on several machines. How to efficiently and securely synchronise all of them?

We see the demand for solution to this problem and the engineers are trying to solve it. However we can not provide it right now. Sorry!

However nothing is lost. There are other methods. In one of the next part we shall look into using S3, MongoDB's GridFS and other methods of storing static while, while keeping the application scalable.

Creating scalable application

So now know should know how these scalable applications work and what they provide, how to create one? First let's see the rhc command line tools. There it's as simple as adding the -s switch to the create command

rhc app create <name> ruby-1.8 -s
rhc app create <name> ruby-1.9 -s

and you can also create the scalable application in the web interface.

On the second page called "Configure and deploy the application" you change the scaling options as depicted on the next three pictures.

No scaling by default

Scaling selection

Scale web traffic

Conclusion

Once you have a scalable application you will use it as you are used to from non-scalable one. The only difference is that the platform will scale-up and scale-down based on the load coming to your project. And at this time you have to do a little bit more work to get a true shared filesystem with a scalable application.

In case you want to scale by hand, we will gladly help you with that. Check Manual Scaling Using Marker Files.

What's Next?