How can we improve the performance of RailS Applications ?, Improve rails
Is rails slow?
「 Railway is slow 」. You may have heard of this joke. What about our Rails framework?
If Rails is slow, how to improve the performance of Rails apps becomes a top concern for developers.
You may have heard of many ways to improve the performance of the RoR APP. They are difficult and easy to use. We need to select one of them to help developers get rid of the performance dilemma.
Here are several different ways to improve the performance of Rails Applications.
1. database index
Your APP is limited by database performance. Excellent database indexes can improve your performance by 100 times in large database tables. However, not all Rails developers understand how important this is.
It is easy to add indexes:
class AddIndexToClientIndustry < ActiveRecord::Migration def change add_index :client_industries, :client_id endend
Next we will compare whether there is any Index.
If there is an Index:
CREATE INDEX addresses_addressable_id_addressable_type_idx ONaddresses USING btree (addressable_id,addressable_type);t1 = Time.now c = Company.find(178389) a = c.addresses.firstt2 = Time.nowputs "---Operation took #{t2-t1} seconds---”Result with index:---Operation took 0.012412 seconds---
No Index:
DROP INDEXaddresses_addressable_id_addressable_type_idx;t1 = Time.now c = Company.find(178389) a = c.addresses.firstt2 = Time.nowputs "---Operation took #{t2-t1} seconds---”Result without index:---Operation took 0.378073 seconds---
0.378073/0.012412 = 30.46 no index is 30.46 seconds slower than indexing.
Therefore, engineers can add Indexes to all referenced parameters or other frequently queried parameters. However, you cannot add too much because each database increases the database Size, which affects performance.
2. Number of database queries
RoR makes programming faster, but in turn makes it difficult to control the number of database queries for each request. For example, if each Client has one or more Industries. We want to display the Client List and their Primary Industries:
<% @clients.each do |client| %> <tr> <td><%= client.id %></td> <td><%= client.business_name %></td> <td><%= client.industries.first.name %></td> </tr><% end %># app/controllers/clients_controller.rbdef index @clients = Client.allend
If there are 50 Clients, there will be 51 database queries:
Processing by ClientsController#index as HTML SELECT "clients".* FROM "clients" SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 1 LIMIT 1 SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 2 LIMIT 1 SELECT "industries".* FROM "industries" INNER JOIN "client_industries" ON "industries"."id" = "client_industries"."industry_id" WHERE "client_industries"."client_id" = 3 LIMIT 1 …
Solution: Eager Loading
# app/controllers/clients_controller.rbdef index @clients = Client.includes(:industries).allend
Currently, there are only 2 to 3 queries, not 51 queries:
Processing by ClientsController#index as HTML SELECT "clients".* FROM "clients" SELECT "client_industries".* FROM "client_industries" WHERE "client_industries"."client_id" IN (1, 2, 3) SELECT "industries".* FROM "industries" WHERE "industries"."id" IN (1, 5, 7, 8, 4)
3. Reduce memory usage
- Only use the truly needed gem
- Load objects during use
- Batch Processing of massive data.
An example of using real data -- find_each:
Using find:
t1 = Time.now Company.where(:country_id=>1).find do |c|puts "do something!" if ['Mattski Test'].include?(c.common_name)endt2 = Time.nowputs "---Operation took #{t2-t1} seconds---”
Result:
1 query, taking 46.65 seconds
Now using find_each:
t1 = Time.now Company.where(:country_id=>1).find_each do |c| puts "do something!" if ['Mattski Test'].include?(c.common_name)end t2 = Time.nowputs "---Operation took #{t2-t1} seconds---"
Result:
100 queries, taking 15.53 seconds in total (3x faster)
There are also situations where the query speed is higher than the query speed.
4. Use Cache
The use of cache has a huge impact on performance. First, make sure that the data model is correct. The cache can help you hide structure problems.
Object Cache
When the object cache is used, you should remove the include of the query method to avoid the association query's inability to use the cache.
Query Cache
If real-time query is not required, you can use memcache-client to cache the query results to memcached.
Partial page Cache
The object cache and query cache both reduce the database access load, but if the RoR load is high, you can only rely on partial page cache.
「 Web websites commonly use partial page caching. One drawback of partial page caching in Rails is that the query statement corresponding to the Action in the page query result should be placed in the View, otherwise, the query in each Action will still be executed, but this will damage the MVC structure of the program code. In this case, another Cache plug-in, better rails caching, can be used to Cache the query statements in Action while caching the page .」
5. Make web requests faster
Only a small number of available processes are used to serve web requests. Therefore, you need to make web requests faster. Ideally, the web process is generally completed within milliseconds. 1 to 2 seconds is slow, and more than 10 seconds is very slow. If your web request is slow, your Rails APP will not be able to support a large number of users at the same time.
Solution: run in the background
Run delayed jobs in the background for long-running projects to release your web process to solve more requests.
6. Performance monitoring
Monitor the performance of the APP to find out which part of the operation is slow or even locate the problem quickly. You can use the best OneAPM monitoring tool of domestic application performance monitoring.
OneAPM for Ruby can go deep into all Ruby applications to complete application performance management and monitoring, includingCode LevelVisibility of performance problems, fast identification and tracing of performance bottlenecks,Real User ExperienceMonitoring, server monitoring, and end-to-end application performance management. Tracing performance bottlenecks include SQL statements, third-party APIs, Web Services, Caching Layers, and background tasks with poor performance.
The figure shows the overview page using OneAPM for monitoring. Here, you can have a preliminary impression on the time consumption of requests on the server side. You can intuitively see indicators such as the flat response time, throughput, and execution times of web tasks, backend tasks, databases, and external services at different times. In the figure, the response time of web tasks peaked, slow response speed.
In order to further identify the problem, click the web transaction interface to further understand the proportion of slow Transaction Response Time and quickly locate the problem.api/medicines/index
The response time is long.
Click the wrong request address to list the URL of the error, the first and last occurrence time, the number of errors, the Agent name, error information, and stack information.
Good application performance monitoring often requires a lot of time and effort to achieve, so selecting an excellent third-party monitoring tool will greatly improve the O & M efficiency, which is of great help to improve the performance of Rails apps.
7. Use a memory database
When the query and sorting are completed in the memory, the database will run faster, and they need to run slowly on the disk.
Solution:
- Limit the size of the database to ensure it is fully suited to memory.
- Remove non-urgent information from the primary database and to the secondary database or elsewhere.
- If you need a large amount of storage, consider using non-relational databases.
8. More performance suggestions:
- Use a content delivery network for static files, such as AWS CloudFront.
- Use delayed loading for the add-on that takes 1-2 seconds.
- Use the service-oriented architecture to synchronize some processes on the managed stack.
I believe that selecting one or more suitable performance improvement methods can make the RoR APP more satisfying to users.
Note: This article provides a reference and translation of some content shared by Matt Kuklinski on slideshare about improving Rails performance.
This article is compiled by OneAPM engineers. OneAPM is an emerging leader in the application performance management field. It helps enterprise users and developers easily achieve slow real-time crawling of program code and SQL statements. For more technical articles, visit the official OneAPM blog.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.