You created a web application with the help of Ruby on Rails, and it seems like its business logic works correctly, the user interface is intuitive, and the design pleases the eye. But, are you sure that it will really meet all the expectations of its users? All these advantages are practically insignificant if, when using your web application, the user experiences lagging and slow responses when operating other running programs. This may even happen if, when testing this software solution for performance, you previously received quite satisfying results. Can you guess why? It could be because testing is performed on modern devices, which can handle an even more complex application easily.
So, what do you do next? Is it possible to prevent such an annoying blunder while still in the development stage? Our answer is “yes,” of course. In this article, we will provide a brief manual, the implementation of which will take no more than 5-10 minutes. Have we caught your attention?
Why is it Important to Stress-test your Application?
Even a decade ago, users were not as "spoiled" as we are today by such a wide variety of web applications. If a program loaded and worked properly, it was good enough. Today, these two requirements are no longer considered sufficient. Less than half of the users of your web resource will continue to use it if the pages take over three seconds to load and, ideally, it would not take more than 1.5 seconds, a threshold set by Google. For developers, this fact does not seem very assuring, as they likely want to insert more pictures and animations, and add some advanced functionalities to their sites. Is there a way to compromise? After all, even this five year old statistic states that 53% of commercial sites lose part of their profits simply because their pages take too long to load. In addition, a dozen years ago, representatives of Amazon made the sensational statement that even a difference of 100 milliseconds can significantly increase the level of conversion and, as a consequence, the turnover of network trading platforms. Have we now convinced you that the performance of an app is an incredibly important parameter that can both make your web application popular, or reduce its ratings, at the very minimum? Let’s review ways to improve it.
Cool Tips for Ruby on Rails app Speed Optimization
So, how do you optimize the speed of the Ruby on Rails app? Below, we’d like to bring to your attention a small tutorial made up of ten great recommendations, which will help provide a constructive assessment of the speed of your application and whether to conduct Rails performance tuning.
1. Determine your Application’s Current Level of Performance
One of the first things that is done when you visit a hospital is the measurement of your vitals, such as body temperature, heart rate, etc. Without this data on your current health state, no doctor can establish a clear diagnosis. The same applies to performance of an app. If you do not know the exact efficiency of your application, any activities with respect to Rails performance optimization may be completely useless. In the case of gaming web applications, performance is easy to assess. If the frame rate does not fall below 30 fps in the most complex scenes, you’re off to a good start (although not ideal, as the benchmark value is 60 fps). A completely different situation is experienced with functional software. How do you evaluate their performance?
In order to measure the speed of the software you are testing, you can take advantage of New Relic - an absolutely amazing software monitoring service, currently unrivaled. Its main advantage (in addition to detailed and multi-criteria analysis of the tested application) is a free version, which can even work locally. Popular cloud-based software development and deployment platform Heroku, contains a log2viz function which collects and monitors app’/website’s statistical data from the Heroku log stream. It is basically, an open-source demonstration of the logs-as-data concept for Heroku apps. Are the capabilities of log2viz not enough in your case? No problem, you can employ the Librato solution - real-time cloud monitoring service which provides more detailed information about the operation of the program under testing. Three other very useful functions of Heroku are load_avg_1m, load_avg_5m and load_avg_15m, which display the average loads for the last 1, 5 or 15 minutes respectively. Need even more detailed stats? Check one of the solutions proposed by Capterra or Hayden James. Moreover, most corporate grade operating systems contain built-in resource monitoring tools. As for us, our absolute favorite is the Locust framework, which allows for implementation of load testing procedures by "bombing" your application with requests, imitating a whole group of users.
2. Try Using Different Hosting
You have successfully implemented our last recommendation, and now your web application is thoroughly tested by all sorts of speed analyzers. When tested in a development environment condition, it literally flies but, after the launch of the project to production, user feedback may state that page loading takes too long. How can this be? You fixed the time of the server response to below 100 milliseconds, but the real users speak about much longer waits. Our second recommendation is to try changing the web hosting provider. In addition, you may employ the services of a content delivery network (CDN), a geographically distributed network infrastructure with a 100% guaranteed delivery of data packets to the destination from the server, with minimum amount of hops, even if communication is lost between individual nodes.
3. Reduce Sizes of Images and Tables
4. Reduce Garbage Collector Call Amounts
Are you aware that each time the garbage collector launches, the implementation of your main code is suspended for 100-400 ms? This issue is serious enough not to ignore. Before you start writing code, carefully understand how the Ruby classes and libraries work. In particular, very carefully handle the ‘reject’ and ‘reject!’ methods, which duplicate the array specified as the input parameter.
5. Minimize the Number of Database Requests
Do not overuse the database connection. As an example, suppose you want to check if the user performed some activity in your app (sent a message). Instead of downloading all the messages from the database, in general, and looking for those that were left by a particular user, you can perform a single query with the keyword SELECT COUNT, which will indicate whether there were any active interactions with the server (for instance, using such a command as Forum.messages.count (:conditions => ["user_id =?", current_user.id]) > 0).
6. Correctly Index the Database
You created the application in RoR and it would seem that it works perfectly. Ruby speed, when page loading is equal or lower than the coveted 1.5 seconds is achieved, and this indicator is provided for all users, regardless of their geographical location. Then, database integration is implemented and, with time, it gradually expands, causing your software to start lagging catastrophically, at this stage. How can you cope with this problem? Let’s discuss one of the most advanced ways to make your Rails app faster - conduct indexing. Within databases, the index is an auxiliary structure that can speed up the process of searching for the required records. Instead of step-by-step comparisons of each record with the required parameters, the indexes allow for analyzation of their contents quickly, as happens with the subject index in a regular book. What is the subject index? It is an alphabetically or,in some other way, sorted list of keywords by which you can quickly find the page you need. In an indexed DBMS, the index search is quite similar. With a specific search key, the index automatically redirects the request to the specific record. Let us consider a particular example for applications based on Ruby on Rails. Say you created a list of contacts, each record of which contains three attributes: number, name, and phone. You’ll notice on your smartphone, for example, that you can search the list of contacts not only by the name but by the phone number, as well. Do you want to implement something similar in your web application? Excellent - the indexes and the ActiveRecord template will help you with this. By indexing all calls with phone numbers and resorting to ActiveRecord::Migration method, we get something like:
class Add_New_Index_To_Contact <:migration def change add_new_index :contacts :number_of_phone end>
Now, if you need to find a record in the contacts by phone number, the query will be processed as quickly as possible as the DBMS will know exactly where to look for the required field.
7. Minimize the Use of Certain Methods
Some methods in Ruby consume a lot of resources. For example, if you use methods such as ‘find_by()’ and ‘find_all_by()’, your application may begin to seriously slow down. In this situation, we generally recommend opting out of using these two methods, in favor of the above mentioned indexation.
8. Turn Caching On
Were previous recommendations not effective enough? Try turning to Rails caching next. Cache pages, actions, SQL requests, assets, and fragments - selecting what you need, in your case. This will help improve Rails performance in cases where your application has data that does not change during use. But do not rush to exercise such measures. You should clearly realize that this is the last resort, and ensuring that the cache does not lose its relevance over time is a fairly capacious and complex task. So, what are the advantages of this technique? By caching data with ActiveRecord, you can store user requests in the memory without having to, once again, connect to the DBMS. In fact, the Rails cache can facilitate web application optimization if user manipulations involve complex requests to the database.
9. Use the Bullet Gem
Do you know about such the helpful Ruby gem, Bullet? If not, we strongly recommend using it to improve code performance. If you work with RoR constantly, you probably know what "N+1” requests are. If not, let us explain. An “N+1” request is when, during a certain cycle for N elements, N+1 iterations are executed. When the total number of simultaneously running iterations is tens or even hundreds of thousands, application begins to lose performance. There is a way out, and Bullet helps in eliminating this problem. Each time Bullet discovers overperforming cycles in your code, it will display a warning on the screen so that you can use the method of impatient link loading or cache counters.
10. Select the Right Session Storage
Depending on your needs, you can store data on the client side, in the CookieStore, in the DRb Store, in the MemCache Store (this is the most recommended external cache storage), in the Redis storage or in the ActiveRecord Store. While writing the code, it is very important to understand where the data packets received after client interaction with the server will be sent (as we indicated above, the cache is not always the optimal solution).
How to Speed Up the Ruby App: Final Thoughts
All the recommendations provided in this guide are capable of improving the performance of your RoR-based web application with the least possible effort and time. If you have no previous experience or resources required for Ruby on Rails performance tuning, you can contact our experts today. We have a staff of highly trained professionals with years of experience in the development and efficiency profiling of RoR-based applications.