Trong các ứng dụng Rails, chúng ta thường ít để ý tới performance bởi vì dữ liệu chúng ta vẫn còn ít, chưa đủ để lm chậm hệ thống.
Nhưng trong một số dự án lớn, thì việc cải thiện performance lại trở nên rất quan trọng. Việc làm đầu tiên là chúng ta sẽ phải là
loại bỏ N+1 query, sau khi loại bỏ xong mà hệ thống chúng ta vẫn chậm thì cần phải sử dụng Cache dữ liệu để tối ưu.
1. Cách hoạt động
Model Caching hoạt động bằng cách sử dụng 1 bộ nhớ đệm để lưu dữ liệu trong lần load trang web đầu tiên. Trong các lần
truy cập tiếp theo, dữ liệu chỉ việc lấy từ bộ nhớ đệm ra, chứ không cần phải query từ DB nữa. Từ đó trang web chúng ta
sẽ cải thiện được performance, người dùng sẽ cảm thấy được trang web của chúng ta nhanh và mượt hơn.
Bộ nhớ đệm ở đây mình sử dụng Redis. Bởi vì redis là một in-memory data structures store, dạng lưu trữ cấu trúc dữ liêu,
lưu trữ dạng key-value ở trong bộ nhớ chính(RAM). Chính điều này đã làm cho Redis có tốc độ xử lý nhanh và phục hồi dữ liệu gần như tức thời
2. Caching với Redis
2.1 Khởi tạo Project
Chúng ta sẽ tạo một ứng dụng demo nhỏ có tên là MyPost như sau:
1 2 3 | rails new MyPost rails g scaffold Post content:string |
Chúng ta sẽ sử dụng gem “Faker” để fake dữ liệu
1 2 | gem "faker" |
Sau đó chạy bundle install
và Import dữ liệu như sau:
1 2 3 4 | 100000.times do Post.create(content: Faker::Lorem.paragraph) end |
Ở đây mình tạo 100k record, các bạn cũng có thể tạo nhỏ hơn. Và bh sẽ chạy lệnh rails db:seed
Sửa lại router để root page trỏ vào đúng trang Post của chúng ta
1 2 3 4 | #routes.rb root "posts#index" |
Khi load trang thì sẽ cho kết quả như dưới đây
ActiveRecord mất 60.6ms để thực hiện câu lệnh sql và Views mất 21941.0ms để hiển thị. Như vậy ta có thể thấy rằng ứng dụng của chúng ta chạy rất chậm. Nào bh chúng ta cùng tối ưu chúng nhé.
2.2 Khởi tạo Redis
Chúng ta sẽ cài redis qua lệnh này
1 2 | sudo apt-get install redis |
hoặc xem hướng dẫn chi tiết tại đây
Sau khi cài đặt redis xong thì chúng ta start nó
1 2 | redis-server |
Để kết nối được Redis với ứng dụng thì chúng ta sẽ phải thêm vài gem vào Gemfile, sau đó run bundle install
1 2 3 4 5 | gem "redis" gem "redis-namespace" gem "redis-rails" gem "redis-rack-cache" |
2.3 Caching
Chúng ta setup lại file application.rb để có thể cache được ứng dụng bằng redis
1 2 3 4 5 6 7 8 | module MyPost class Application < Rails::Application [...] config.cache_store = :redis_store, 'redis://localhost:6379/0/cache', {expires_in: 90.minutes} [...] end end |
Ta cần phải tạo ra một Redis instance để có thể gọi được ở bất kì đâu trong ứng dụng Rails
1 2 3 4 | #initializers/redis.rb $redis = Redis::Namespace.new "demo-redis", redis: Redis.new |
Ta sẽ chỉnh sửa lại method index trong posts_controller.rb như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # posts_controller.rb def index @posts = fetch_post respond_to do |format| format.json {render json: @posts, status: :ok} end end private def fetch_post posts = $redis.get "posts" if posts.nil? posts = Post.all.to_json $redis.set "posts", posts end JSON.load posts end |
Chúng ta cùng chạy lại và xem kết quả nào
Ta thấy Views chỉ mất có 13ms để hiển thị và ActiveRecord là 0ms, như vậy Server không hề mất thời gian truy vấn dữ liệu, thay vào đó là lấy dữ liệu từ Redis ra vì thế mà ứng dụng chúng ta chạy rất nhanh.
3. Một số lưu ý
3.1 Sử lý khi redis lỗi
Chúng ta cần phải bắt exception cho trường hợp như này
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # posts_controller.rb def fetch_post begin posts = $redis.get "posts" if posts.nil? posts = Post.all.to_json $redis.set "posts", posts end posts = JSON.load posts rescue => error puts error.inspect posts = Post.all end posts end |
3.2 Dữ liệu sau khi update hoặc delete
Trong trường hợp dữ liệu sau khi update hoặc bị xóa thì trong redis dữ liệu vẫn chưa được cập nhật lại. Vì thế chúng ta cần cập nhật lại dữ liệu trong redis khi gặp trường hợp này
1 2 3 4 5 6 7 8 9 10 11 | #Post.rb class Post < ApplicationRecord after_save :clear_cache private def clear_cache $redis.del "posts" end end |
Caching là một kỹ thuật tuyệt vời để có thể tăng hiệu suất ứng dụng của chúng ta. Hi vọng bài viết sẽ giúp các bạn có cái nhìn về caching
Tham khảo
http://www.victorareba.com/tutorials/speed-your-rails-app-with-model-caching-using-redis
https://www.sitepoint.com/rails-model-caching-redis/