Cải thiện performance cho Rails applications
Mở đầu Có rất nhiều developer phàn nàn về việc các ứng dụng Rails của họ chạy chậm. Nhưng hầu hết trong số đó không hoặc chưa thực sự quan tâm đến việc cải thiện performance cho các ứng dụng của họ. Trong bài viết này, chúng ta sẽ cùng tìm hiểu xem làm thế nào để kiểm soát, phát hiện và khắc phục ...
Mở đầu
Có rất nhiều developer phàn nàn về việc các ứng dụng Rails của họ chạy chậm. Nhưng hầu hết trong số đó không hoặc chưa thực sự quan tâm đến việc cải thiện performance cho các ứng dụng của họ. Trong bài viết này, chúng ta sẽ cùng tìm hiểu xem làm thế nào để kiểm soát, phát hiện và khắc phục các performance issue để giúp các ứng dụng rails chạy mượt mà hơn.
Cũng xin nói qua một chút về performance, performance của hệ thống là khả năng đáp ứng yêu cầu của một hệ thống trong một khoảng thời gian. Nó khác với Scale, performance thường nói đến việc làm sao để đáp ứng nhiều nhất yêu cầu của hệ thống mà không cần update phần cứng, còn Scale là update phần cứng để sao cho đáp ứng được nhiều yêu cầu hơn.
Frontend performance
Để cái thiện performance cho frontend, chúng ta có thể sử dụng một số phương pháp sau:
1. Minify css và Javascript
#config/environtments/production config.assets.compress = true
2. Sử dụng Gzip
# config.ru require ::File.expand_path('../config/environment', __FILE__) use Rack::Deflater # Thêm dòng này run Rails.application
3. Compress images
#Gemfile gem 'paperclip-compression' # Model class User < ActiveRecord::Base has_attached_file :avatar, styles: { medium: '300x300>', thumb: '100x100>' }, processors: [:thumbnail, :compression] end
4. Javascript at the bottom
<script src = "/assets/common.js"></script>
Backend performance
Để hỗ trợ việc tìm kiếm performance issues ở backend, chúng ta có thể sử dụng một số công cụ như New Relic hay Skylight. Với New Relic chẳng hạn, đây là một dịch vụ server monitor dùng để theo dõi giám sát các thông số quan trọng của hệ thống.
Dưới đây là một số performance issue thường gặp và cách khắc phục
1. Avoid N+1 query
Nguyên nhân đầu tiên dẫn đến việc ứng dụng load chậm phải kể đến đó là việc truy vấn nhiều lần vào cơ sở dữ liệu để lấy ra thông tin mong muốn. Ví dụ
# Controller @comments = Comment.limit(10) #View <% @comments.each do |comment| %> <tr> <td><%= comment.article.name %> <%= comment.name %></td> </tr> <% end %> #Console Article Load (0.5ms) SELECT "articles".* FROM "articles" LIMIT 10 (5.6ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."article_id" = ? [["article_id", 1]] (1.2ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."article_id" = ? [["article_id", 2]] (1.1ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."article_id" = ? [["article_id", 3]] ............................. (1.0ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."article_id" = ? [["article_id", 10]] ?
Câu lệnh trên sẽ lấy ra 10 comments, sau đó thực hiện vòng lặp với các comments này truy vấn vào DB lấy ra các article của chúng. Chuyện gì sẽ xảy ra nếu như số lượng comments tăng lên gấp 10 hoặc 100 lần. Để khắc phục điều này chúng ta có thể sử dụng eager loading methods
# Controller @comments = Comment.includes(:article).limit(10) #Query Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."id" IN (1, 2)
2. Sử dụng counter_cache
counter_cache là cơ chế cho phép cache số lượng items của associated model. Có rất nhiều lần chúng ta muốn đếm số object con và hiển thị số lượng object đó ra View, đồng nghĩa với nó là sẽ có tương ứng bấy nhiêu câu query access vào database. Bằng việc thêm mới 1 attribule comments_count trong bảng article và sử dụng counter_cache thì sẽ không có câu query nào được thực thi, thay vào đó rails chỉ trỏ đến trường comments_count trong Article table.
# migrate add_column :articles, :comments_count, integer Article.all.each do |article| Article.reset_counters(article_id, :comment) end # Model class Comment < ActiveRecord::Base belongs_to :article, counter_cache: true end
3. Small Payload
Chỉ lấy những dữ liệu bạn thực sự cần, tránh việc lấy thừa dữ liệu
# Controller @articles = Article.limit(10) # View <% @articles.each do |article| %> <tr> <td><%= article.name %></td> </tr> <% end %>
Thay vào đó hãy sử dụng
@articles = Article.select('name').limit(10)
Kết luận
Có rất nhiều nguyên nhân khiến cho ứng dụng Rails của bạn chạy chậm, nguyên nhân có thể xuất phát từ Frontend hay backend. Sử dụng các công cụ hỗ trợ detective giúp bạn sớm tìm ra được vấn đề , hãy tái hiện các perfomance issue đó ở local và khắc phục chúng dựa vào một số cách trên. Hi vọng một số gợi ý trên có thể phần nào giúp bạn tháo gỡ vấn đề.