12/08/2018, 13:31

Rails Model Caching with Redis

Model level caching hay bị các developers bỏ qua, ngay cả các developers dày dặn kinh nghiệm. Phần lớn là do quan niệm sai lầm. Cache cấp độ thấp rất linh hoạt và bạn có thể làm việc với nó ở bất cứ ứng dụng nào. Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách dùng cache cho models của Rails bằng ...

alt

Model level caching hay bị các developers bỏ qua, ngay cả các developers dày dặn kinh nghiệm. Phần lớn là do quan niệm sai lầm. Cache cấp độ thấp rất linh hoạt và bạn có thể làm việc với nó ở bất cứ ứng dụng nào. Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách dùng cache cho models của Rails bằng Redis.

Cache hoạt động như thế nào?

Bình thường ta truy cập trực tiếp vào ổ đĩa để lấy dữ liệu, điều này khiến ứng dụng của bạn sẽ cần đến một ổ đĩa tốt đắt tiền để làm cho ứng dụng của bạn chạy êm mượt. Nhưng liên tục truy cập như thế sẽ khiến hiệu suất sẽ giảm. Để xử lý điều này ta xậy dựng 1 layer giữa ứng dụng của bạn với database được lưu trên ổ đĩa, được gọi là bộ nhớ cache. Bộ nhớ cache không lưu trữ dữ liệu ngay từ đầu mà khi ta request tới ứng dụng để lấy data trong database, bộ nhớ cache sẽ lưu trữ những dự liệu này để dụng cho các phiên làm việc tiếp theo từ đó sẽ giúp ứng dụng chúng ta không mất nhiều thời gian để lấy data trong database nữa, từ đó cải thiện hiệu suất của ứng dụng.

Tại sao lại là Redis?

Redis là một bố nhớ, theo kiểu key-value. Nó có tốc độ truy cập nhanh, và lấy dữ liệu ra gần như là tức thời. Redis hỗ trợ rất nhiều các cấu trúc dữ liệu khác nhau như: list, hash... Redis rất dễ dàng trong việc cài đặt và sử dụng. Nếu bạn sử dụng resque hoặc sidekiq trong việc quản lý các jobs chạy ngầm thì bạn đang có Redis được cài đặt sẵn.

Cách cài đặt

Chúng ta sẽ download redis và make nó:

$ wget http://download.redis.io/releases/redis-2.8.18.tar.gz
$ tar xzf redis-2.8.18.tar.gz
$ cd redis-2.8.18
$ make

Sau khi chạy những cậu lệnh ở trên ta chờ cho source redis biên dịch xong. Chúng ta sẽ chạy tiếp câu lệnh ở dưới:

$ cd redis-2.8.18/src
$ ./redis-server

Cài đặt Redis vào Rails

Add những gem vào Gemfile

gem 'redis'
gem 'redis-namespace'
gem 'redis-rails'
gem 'redis-rack-cache'

Chúng ta sẽ khai báo cho Rails để sử dụng Redis như một bộ nhớ cache:

# config/application.rb

#...........
config.cache_store = :redis_store, 'redis://localhost:6379/0/cache', { expires_in: 90.minutes }
#.........

Dưới đây là ví dụ cách các bạn lưu trữ dữ liệu vào Redis:

# lưu trữ dữ liệu
$redis.set("test_key", "Hello World!")

# lấy dữ liệu ra
$redis.get("test_key")

Chúng ta đã có những kiến thức cơ bản về Redis, giờ hãy bắt đầu viết 1 hàm helpers:

# app/helpers/category_helper.rb

module CategoryHelper
  def fetch_categories
    categories =  $redis.get("categories")
    if categories.nil?
      categories = Category.all.to_json
      $redis.set("categories", categories)
    end
    @categories = JSON.load categories
  end
end

Ở thời điểm đầu tiên ta chưa có dữ liệu nào trong bộ nhớ cache. Bởi vậy chúng ta sẽ request tới database để lấy dự liệu rồi sau đó lưu chúng vào Redis. Khi ta lưu 1 đối tượng nào đó vào Redis, chúng ta có 2 lựa chọn. Thứ nhất ta sẽ duyệt qua từng phần tử của dự liệu rồi lưu chúng dưới dạng Hash, nhưng cách này rất chậm. Cách đơn giản hơn là chúng ta sẽ lưu chúng dưới dạng JSON. Và từ đó dữ liệu lấy ra chúng ta chỉ cần JSON.load nó.

Để quản lý những dữ liệu sẽ được lưu trữ trong bao lâu ta sẽ sử dụng $redis.expire

# app/helpers/category_helper.rb

module CategoryHelper
  def fetch_categories
    categories =  $redis.get("categories")
    if categories.nil?
      categories = Category.all.to_json
      $redis.set("categories", categories)
      # Expire the cache, every 3 hours
      $redis.expire("categories",3.hour.to_i)
    end
    @categories = JSON.load categories
  end
end

Như code ở trên chúng ta thấy dữ liệu được lưu trữ trong vòng 3 tiếng mới được xóa, bởi vậy nếu trong 3 tiếng đó nếu có 1 category nào được thêm hoặc update hoặc xóa thì dữ liệu được lấy ra để hiển thị sẽ không còn đúng. Chúng ta sẽ thêm 1 callback trong model để mỗi khi update, create or delete thì dữ liệu trong redis luôn luôn là dự liệu chuẩn của Database:

# app/models/category.rb

class Category
  #...........
  after_save :clear_cache

  def clear_cache
    $redis.del "categories"
  end
  #...........
end

Kết luận

Trên đây là bài giới thiệu tổng quan về bộ nhớ đệm cache cấp thấp. Nó rất đơn giản và dễ sử dụng. Hy vọng bài viết sẽ giúp các bạn lập trình đơn giản và linh hoạt hơn

0