07/09/2018, 18:07

Caching with Rails: Caching Strategies - HTTP Caching

Bài viết này tổng quan về việc giúp cho bạn tặng tốc ứng dụng của bạn với caching. Caching có nghĩa là lưu lại nội dung response của 1 request và tái sử dụng nó với các request tương tự. Caching là một cách thường xuyên được xử dụng để tối ưu ứng dụng rails. Bằng cách sử dụng caching, các trang ...

Bài viết này tổng quan về việc giúp cho bạn tặng tốc ứng dụng của bạn với caching.
Caching có nghĩa là lưu lại nội dung response của 1 request và tái sử dụng nó với các request tương tự.
Caching là một cách thường xuyên được xử dụng để tối ưu ứng dụng rails. Bằng cách sử dụng caching, các trang web chạy trên một sever và một database đơn lẻ có thể "đương đầu" với hàng triệu người dùng.
Rails cung cấp một loạt các tính năng caching khác nhau, series bài viết này sẽ hướng dẫn bạn cách sử dụng chúng. Làm chủ nó và ứng dụng của bạn sẽ awesome :)

Các loại caching trong rails là:HTTP, page, actionfragment. Mặc định rails cung cấp cho chúng ta fragment caching. Để sử dụng page và action caching bạn cần thêm 2 gem sau vào Gemfile: actionpack-page_cachingactionpack-action-caching

Ta có mô hình MVC của Rails là:
Client -> routes -> Controller -> (Model <-> DB) -> Controller -> View -> Controler -> Client

Intro

Các bạn hẳn đều đã từng cảm nhận thấy sau mỗi lần các bạn có bất kì chỉnh sửa nào trong các file như js hay css, quá tình load 1 trang web sau đó trở nên thật "rùa" ?

Bằng cách sử dụng các HTTP headers (Last-Modified, ETag, If-Modified-Since, If-None-Match, Cache-Control) để xác định xem trình duyệt có thể sử dụng các phiên bản response được lưu trư local không hoặc nó sẽ request một bản copy mới từ sever. Rails thực hiện điều này bằng HTTP caching, tuy nhiên, caching được quản lý bên ngoài ứng dụng rails.
Có thể bạn đã thấy ở đâu đó những dòng này config.cache_controlRack::Cache, Rack::ETag, Rack::ConditionalGet. Chúng được sử dụng để triển khai HTTP caching.
Mặc đinh HTTP caching có sẵn trong các ứng dụng rails, nhưng đi kèm với no ta có thể dùng thêm Rack::Cache hay Etag để sử dụng HTTP caching như là asset pipeline, hiệu quả hơn assets static.

Asset pipeline

Rails 3.1+ giới thiệu cho chúng ta về khái niệm Asset Pipeline
Bằng việc nối (concatenation) và nén (compression) các asset JS và CSS. Rails thêm vào header của các response như sau:

qua đây mà ngăn chặn việc request lại các asset giống nhau trên các response.

Rack::Cache

Nó như là proxy-cache
Trên môi trường roduction, Rake::Cache đóng vai trò như là một proxy cache trung gian. Tất cả các page với header cache public sẽ được lưu trữ tại đây. Thông qua nó Rails sẽ bỏ qua các request cho resource đã được cache.

Rack::ETag

ETag là một đoạn mã được sever sinh ra cho mỗi file, khi nội dung file bị thay đổi thì ETAG của 1 file cũng sẽ thay đổi theo. Sever cũng bằng cách đó mà phân biệt là đối với request này có cần trả về file mới cho client hay không.

Cache-control

Rails cung cấp 2 loại là** expires_in** và expires_now

expires_in

cùng theo dõi action show sau:

def show
  @company = Company.find(params[:id])
  expires_in 3.minutes, :public => true
  # ...
end

đoạn code trên gán cho giá trị max-age trên header là max-age=180, public

tùy chọn này sẽ ngăn không cho client tiếp tục đòi request trong thời gian chỉ định. Nó thực sự hữu ích đối với các trang web không yêu cầu việc phải update thông tin thường xuyên, sẽ giảm tải cho sever rất nhiều, nhưng nó lại thật tệ đối với các ứng dụng quản lý.

Khi được sử dụng chung với Rake::Cache, cùng xem log trên sever nhé:

Started GET "/companies/2" for 127.0.0.1 at 2012-09-26 14:07:28 +0100
Processing by CompaniesController#show as HTML
Parameters: {"id"=>"2"}
Rendered companies/show.html.erb within layouts/application (9.0ms)
Completed 200 OK in 141ms (Views: 63.8ms | ActiveRecord: 14.4ms)

Started GET "/companies/2" for 127.0.0.1 at 2012-09-26 14:11:10 +0100
Processing by CompaniesController#show as HTML
Parameters: {"id"=>"2"}
Completed 304 Not Modified in 2ms (ActiveRecord: 0.3ms)

Các request cho cùng một resource chỉ được controller trả về một lần trong khoảng thời gian quy định

lưu ý: đối với reqquest status 200 là sever có trả về file mới, client có thực hiện download, còn với reqquest 304 là client sử dụng lại các file đã được lưu sẵn trong cache, không cần phải download lại các file mới trên sever.

expires_now

Um, nghe tên có vẻ các bạn đã biết công dụng của nó rồi nhỉ, nó sẽ set giá trị cho cache-control: no-cache, ngăn chặn trình duyệt lưu lại cache

def show
  @person = Person.find(params[:id])

  # Set Cache-Control header no-cache for this one person
  # (just as an example)
  expires_now if params[:id] == '1'
end

Khi debug thì các bạn nên lưu ý lại 2 option này nhé.

Một số lưu ý:

  • Trong các cách sử dụng tham số cho HTTP Headers để thực hiện HTTP Caching có thể chia làm 2 loại:
    Strong Caching Header: Expires và Cache-Control.
    Weak Caching Header: Etag và Last-Modified.
  • Ứng dụng của bạn chỉ nên sử dụng một Strong Caching Header và một Weak Caching Header vì cơ chế tương tự nhau, nếu sử dụng cả hai cùng một lúc sẽ dư thừa.
  • Nếu đồng thời sử dụng Expires và Cache-Control thì Cache-Control sẽ được ưu tiên hơn.
  • Nên sử dụng Cache-Control hơn là Expires vì tính linh động của nó.
  • Nên sử dụng Last-Modified hơn là Etag vì có thể Etag sẽ gặp vấn đề khi config với Apache2.
  • Với các file tĩnh ít khi thay đổi thì nên đặt thời gian còn hiệu lực là khoảng 1 tháng đến 1 năm.
  • Nên sử dụng thêm việc đánh version cho các file tĩnh để khắc phục nhược điểm của Expires cũng như Cache-Control.

Tham khảo từ:

https://devcenter.heroku.com/articles/http-caching-ruby-rails
http://hawkins.io/2012/07/advanced_caching_part_1-caching_strategies/
https://devcenter.heroku.com/articles/caching-strategies
https://viblo.asia/p/http-caching-6BAMYknzvnjz

0