7 Completely Legal Rails Performance-Enhancing Techniques

  

Rails Performance-Enhancing TechniquesIs your app bogging down under the weight of increased traffic? Read this post to find out how to boost Rails performance and turn your app into Usain Bolt.

You may have to follow a few of the items listed here or all of them. Before you make any changes, make sure you identify the problem correctly and measure your application's response time. An improvement in the response time tells you that your changes are correct.

At Engine Yard, we help you scale your Rails application. For example, we make it easy to add servers quickly. But we also investigate that adding servers is the correct action.

We've seen a few customers add servers when their site slows down as a reflex. We investigate and find out that the database is the problem. Adding more servers, in this case, doesn't help.

We'll talk about possible improvements to your infrastructure and Rails application.

INCREASING THROUGHPUT

LOWERING RESPONSE TIME

RAILS PERFORMANCE: INCREASING THROUGHPUT

Adding Servers

More servers means more Unicorn/Puma/Passenger processes handling requests. Rails scales horizontally well. You can add as many servers as you want with only a few gotchas.

  • Upload files on S3 or a shared filesystem. Don't use the local filesystem. See AWS Image Storage with S3 and EFS.

  • Adjust the maximum number of connections allowed on your database if necessary. The additional Ruby app servers will increase the number of connections to your database so make sure you don't reach the limit.

  • As mentioned above, investigate the problems before adding servers. You don't want to waste money with unnecessary servers.

Aside from adding servers, you can also change the server size. In AWS, EC2 instance types have a specific amount of resources. Bigger instances with more vCPUs and memory can run more Ruby processes.

Observe the memory and CPU utilization of your Rails application. If your EC2 instance goes into swap without high CPU utilization, consider instance types with more memory. If your EC2 instance has high CPU utilization without going into swap, consider Compute Optimized instances.

Auto Scaling

Auto Scaling is an AWS feature that adds or removes instances automatically. You can scale based on schedule or on demand.

If you know the time of the day your application gets a lot of traffic, you can set Auto Scaling to add more instances during that time. Auto Scaling on demand adds instances based on a policy. For example, you can set a policy that adds instances when CPU utilization is at 70% for 15 minutes.

Load Balancers

A load balancer distributes requests to multiple servers. It is the entry point of your application. When traffic increases, make sure your load balancer can handle the number of requests coming in.

In small setups at Engine Yard, we use HAProxy as a load balancer. This runs on an EC2 instance together with the Rails application. This is a cost-effective setup for small to medium applications.

The EC2 instance running HAProxy is a single point of failure. If it goes down, the whole site goes down for a minute while Engine Yard points your IP address to a different EC2 instance. This process is automated.

AWS Elastic Load Balancers are recommended for applications with critical uptime needs. ELBs are managed by AWS and can handle millions of requests per second. Use managed load balancers if your Cloud provider offers them.

RAILS PERFORMANCE: LOWER RESPONSE TIME

Caching

Caching improves the response time of your Rails application. Lower response time results in more requests that a single server can handle. If you have the option to speed up your Rails application, do it. You can have fewer servers when your application is faster.

Caching works by storing content on a cache store. It is faster to get the content from the cache store than generate it again, which results in lower response time.

Rails support Page Caching, Action Caching, and Fragment Caching. For the first two, you need to install the actionpack-pagecaching and actionpack-actioncaching gems respectively.

Page Caching stores the whole page to the filesystem regardless of your cache store. The HTML page is served by your webserver (e.g. Apache or Nginx) which is faster than passing the request to Rails. However, this only works if the page is the same for all users.

Action Caching is similar to Page Caching but the request goes through the Rails stack. You can use before filters with Action Caching which you can't do with Page Caching.

Use Fragment Caching if you can cache only certain parts of a page. This is more widely-used than the first two and thus is included in Rails by default.

Read more about Caching with Rails here.

Content Delivery Network (CDN)

Rails assets like images, Javascript files, and stylesheets are static files best served by the webserver. Request to these files shouldn't reach your Rails application at all.

You can also use a CDN to speed up the delivery of these static files. CDN stores files on servers around the world. Your users automatically get the files from the server nearest to them for better performance.

Using a CDN for Rails assets is done with 1 line on config/environments/production.rb. Set config.action_controller.asset_host to your CDN host. On your CDN, point the origin of your Rails assets to your domain.

If you're using AWS, check out their CDN service CloudFront.

Database

Slow database queries increase the response time of your Rails application. Measure the time spent on the database for each request. If you see a slow request due to the database, you may have to add an index or adjust your query. Run the EXPLAIN command to get more insight.

Adding more Rails servers won't speed up your application if the problem is with the database. You can even make things worse because adding more servers results in more connections to the database.

Use database replicas if your database can't handle the queries coming in. Your Rails application will read data from a database replica but it will write data to the database master. Rails doesn't support reading from replicas out of the box. Among the gems that provide this feature, Octopus seems to be the only one that's maintained.

More advanced setups are master-master and database sharding. These add complexity to your setup so think carefully before using them.

Using a single database can support a big application. Upgrade to a bigger server with more resources before considering more complicated setups.

Ruby App Server

Three popular Ruby app servers are Unicorn, Puma, and Passenger. You can't go wrong in choosing any of these 3. Two features you want to check are multiprocesses and multithreading support.

Ruby has a Global Interpreter Lock (GIL) so only one thread can run at a time. To serve multiple requests at the same time, run multiple processes. All 3 app servers mentioned above support running multiple processes. This feature is built-in and you don't need to manage each process individually.

Running multiple threads, even with the GIL, can increase the number of requests being processed. A thread processing a request waits for I/O, say a database performing a query. Another thread can run while the other thread is waiting.

Puma and Passenger Enterprise have multithreading support. Unicorn does not.

Which one should you choose? Puma is the default app server in Rails. If you can afford a license for Passenger Enterprise, that's a good option. Unicorn is still in use by large companies like GitHub.

Choose any of the 3 and your decision is correct.

Summary

You can improve the performance of your Rails application with one item on this list or all of them. The changes you need to make depend on your application. Measure your response time before making changes.

To lower your response time, use caching, check for slow queries on your database, and select the correct Ruby app server.

To increase your throughput, add more servers, use Auto Scaling, and use Elastic Load Balancer or similar.

If you  would like help improving the performance of your Rails application, get a free Code Consultation.

Free Ebook:
Should I Hire DevOps or Outsource to a Provider?

You have to invest in your infrastructure: Do you hire DevOps for this critical function, assign it to your already overworked engineers, or outsource to a provider that offers full-stack capabilities?

Should I Hire DevOps?

Christopher Rigor

 
DevOps Support Manager, Asia-Pacific at Engine Yard. Organizer of @RubyConfPH. Speaker. Interested in automation, Kubernetes, Docker, Deis, ops, Ruby.
Find me on:

Comments

Subscribe Here!