CACHING ON RAILS

Tại sao chúng ta lại sử dụng cache?

  • Cache có thể tăng hiệu năng sử dụng của hệ thống
  • Cache giảm tải việc truy xuất trực tiếp vào database
  • Cache tăng tốc độ truy cập ứng dụng web lên nhiều lần so với việc không sử dụng cache.
  • Cache ứng dụng trong Rails web app là một ứng dụng web hoạt động theo hình thức Request và Responce dữ liệu đầu vào là URL và các tham số và kết quả trả về là nội dung HTML..

nếu phân tích một luồng resquest và responce thông thường của ứng dụng web chúng ta có thể mô tả thành các bước như sau:

Request -(1)-> [Controller/Action -(2)-> [[Model -(3)-> DB -(4)]-> View -(5)]] -> Response

Tại mỗi bước thì ứng dụng web có thể trả về kết quả ngay lập tức mà không cần phải tính toán gì nếu như đã có kết quả lưu trữ trong cache trên webserver.

Dựa vào luồng đi của ứng dụng web ta có thể phân cache ra thành 5 loại như sau:

Page: Nguyên cả trang HTML ứng với URL nhất định được lưu vào cache, các truy cập tiếp theo đến cùng URL này nhận được ngay kết quả từ web server. Chương trình không phải tính toán gì, thậm chí không biết là đã có request vì web server không báo.

Action: Chương trình biết là có request, nhưng trả về ngay kết quả mà không cần động vào Model hay View.

Fragment: Chỉ một phần HTML của trang được lưu.

Object: Object nào đó (có thể không phải là chuỗi kí tự HTML) được lưu.

SQL: Khi cùng câu lệnh SQL được gọi đi gọi lại, thì chỉ lệnh đầu tiên được gửi đến DB server

Sử dụng cache trong rails 3

để enable chức năng sử dụng cache trong rails :

  • thay đổi config trong file config/deverlopment.rb hoặc môi trường khác như sau:
config.action_controller.perform_caching = true
  • Page Caching

rails cung cấp một cách cài đặt

caches_page :index

để thông báo cho webserver tự động generate trang HTML tĩnh và sử dụng cho các lần request tiếp theo từ controller Product action là index. mặc định thì trang HTML này sẽ được tạo ra tại folder /public bạn cũng có thể thay đổi chúng bằng cách thay đổi config trong

config.action_controller.page_cache_directory=new_cache_path
class ProductsController < ActionController
caches_page :index

  def index
    @products = Products.all
  end

  def create
    expire_page :action => :index
  end
end

ở đoạn code trên bạn sử dụng

expire_page :action => :index

trong action create để thông báo cho webserver hủy bỏ trang tĩnh index đã lưu trên webserver khi có một record mới được tạo. điều này nghĩa là khi bạn gọi lại trang index lần sau đó thì server sẽ thực hiện nạp lại trang index vào trang HTML bà bạn sẽ nhìn thấy dữ liệu của một record đã được thêm mới bạn cũng có thể cấu hình cho webserver (Ngix) sẽ tự động zip lại page khi gửi trả lại phía client để tăng tốc độ truy cập bằng cách bật thuộc tính

gzip_static:on trong setting server Ngix.
location /  {
  gzip_static on; # to serve pre-gzipped version
}

sau đó bạn có thể set thuộc tính gzip bằng cách

 caches_page :index, :gzip => :best_speed
  • Action Caching

Có những nhươc điểm của việc sử dụng cache page là với những trang mà yêu cầu quyền truy cập thì bạn không thể sử dụng dc. do request sẽ được trả lại ngay từ webserver nên ứng dụng không thể fillter được request với một trang đã được cache này từ đó chúng ta có cache_action

class ProductsController  :index
  caches_action :index
  def index
    @products=Product.all
  end
  def create
    expire_action :action => :index
  end
end
  • Fragment Caching

Fragment caching là việc cache lại từng phần tử thông tin của trang để thực hiện việc caching từng phần tử của trang ta làm như sau:

 <% cache(:action => 'index', :action_suffix => 'all_products') do %> All available products: <% Product.all.each do |p| %> <%= link_to p.name, product_url(p) %> <% end %> <% end %>

đoạn code trên chúng ta đang cache lại thông tin của tất cả các product lấy ra từ db trong block

 <% cache() do end %>

để dọn dẹp cache chúng ta sử dụng

 <% expire_fragment(:controller => 'products', :action => 'recent', :action_suffix => 'all_products') %>

khi sử dụng doạn code trên thì rails sẽ thông báo cho sever biết để hủy cache có suffix: ‘all_products’

  • Sweepers

Sweeper sử dụng để quản lý exprire cache nếu bạn có nhiều cache được sử dụng ở nhiều nơi thì việc sử dụng sweeper giúp bạn dễ dàng quản lý chúng bằng để sử dụng sweeper bạn cần làm như sau.

VD bạn khai báo các hàm callback để thực hiện expired cache với model Product

class ProductSweeper < ActionController::Caching::Sweeper observe Product

This sweeper is going to keep an eye on the Product model

If our sweeper detects that a Product was created call this

def after_create(product) expire_cache_for(product) end

If our sweeper detects that a Product was updated call this

def after_update(product) expire_cache_for(product) end

If our sweeper detects that a Product was deleted call this

def after_destroy(product) expire_cache_for(product) end
private def expire_cache_for(product)

Expire the index page now that we added a new

product expire_page(:controller => 'products', :action => 'index')

Expire a fragment

expire_fragment('all_available_products') end end

và sau đó bạn khai báo trong Product controler như sau:

class ProductsController < ActionController before_filter :authenticate caches_action :index cache_sweeper :product_sweeper def index @products = Product.all end end
  • SQL Caching

Nếu bạn sử dụng câu lệnh truy vấn lại nhiều lần rails sẽ hỗ trợ bạn lưu lại kết quả truy vấn vào cache VD: nếu bạn chạy 2 lần một câu lệnh truy vấn như bên dưới thì rails sẽ chỉ chạy một lần duy nhất thao tác vào db. các lần sau đó rails sẽ tự động lấy kết quả từ trong memory.

class ProductsController < ActionController def index # Run a find query @products = Product.all ... # Run the same query again @products = Product.all end end

Tuy nhiên việc cache lại câu lệnh sql trong rail chỉ có tác dụng trong chính hàm đó nên nếu bạn muốn sử dụng rộng rãi việc cache lại kết quả của lệnh truy vấn thì bạn sẽ phải sử dụng cache ở chế độ thấp hơn.

  • Cache Stores

Rails hỗ trợ việc lưu trữ cache bằng nhiều cách khác nhau.

  • Cache trên memory

nếu config lưu trữ trên memory thì rails sẽ thực hiện lưu trữ mọi thông tin trên memory của cùng một process. rail có thể lưu trữ cả chuỗi và các rails Object trong cache trên memory. setting:

ActionController::Base.cache_store = :memory_store

tuy nhiên việc lưu trữ trên memory với rails không phải là thread saft nên không thể dùng với ứng dụng multithread được Để sử dụng thread safe thì chúng ta phải sử dụng synchronized_memory_store thay vì memory_store

  • Cache tron file

cache lưu trữ thông tin của ứng dụng trong rails default là được lưu trữ trong file với đường dẫn mặc định là tmp/cache lợi thế của việc lưu trữ cache trong file là có thể truy suất từ các process khác nhau trong cùng một server setting:

ActionController::Base.cache_store = :file_store, "/path/to/cache/directory"
  • Cache DRb Store

Cache được lưu trữ trong một vùng nhớ chia sẻ mà các process cùng truy cập đến tuy nhiên bạn sẽ phải quản lý việc sử dụng process DRB này. setting

ActionController::Base.cache_store = :drb_store, "druby://localhost:9192"
  • Memcache Store

Giống như cách lưu cache bằng DRb store. tuy nhiên Memache sử dụng cache dạng Danga’s memcached trong khi đó DRb store sử dụng default gem memcached-client (phổ biến nhất trong các ứng dụng hiện nay) setting:

ActionController::Base.cache_store = :memcached_store, "localhost"

memache có một số ưu điểm như: có thể sử dụng loadbalance and clustering với nhiều server memcached khác nhau. việc loadbalancing có thể được thực hiện giữa nhiều server (live) với nhau. khi một trong các server chết thì bỏ qua và chỉ thực hiện với các server đang sống

Compressed MemcachedStore Đây là cách lưu trữ có hỗ trợ nén dữ liệu sử dụng GZIP trong memcached

 ActionController::Base.cache_store = :compressed_memcached_store, "localhost"