Tối ưu hiệu năng website – Cache

Tối ưu hiệu năng website – Cache

Bài đầu tiên là về vấn đề cache. Web cache là việc lưu trữ bản sao của những tài liệu web sao cho gần với người dùng. Nó có thể chia ra làm hai cấp độ:

Browser cache

Hầu hết các trình duyệt đều hỗ trợ cache. Các tài nguyên nên cache là các tài nguyên ít thay đổi như JS, CSS, ảnh và các file media khác (pdf, flash,…). Chuẩn HTML 1.1 cung cấp các HTTP response header sau phục vụ cho mục đích cache:

Strong caching headers

Gồm ExpiresCache-Control. Khi có yêu cầu tới các tài nguyên đã từng truy cập trước đó, trình duyệt sẽ kiểm tra các trường này trước khi quyết định gửi request lên server hay lấy từ bộ nhớ cache (trừ trường hợp người dùng Refresh lại trang web, trình duyệt luôn gửi request).

  • Expires: là thời điểm hết hiệu lực của tài liệu được cache mà chỉ khi nào quá thời điểm này, trình duyệt mới gửi request lên server để tải lại tài liệu. Giá trị của trường này luôn là thời gian theo GMT.
    Expires: Fri, 30 Oct 1998 14:19:41 GMT
    Ưu điểm của Expires là nó được hỗ trợ rộng rãi do được giới thiệu từ chuẩn HTTP 1.0. Tuy nhiên Expires sử dụng thời gian tuyệt đối nên thời gian tại server và tại nơi cache luôn phải chính xác. Thêm nữa, server phải “nhớ” cập nhật expires date, nếu không khi qua thời điểm này, số lượng request tới server sẽ tăng mạnh gây quá tải cho server.
  • Cache-Control: linh động hơn Expires, nó có thể bao gồm các thông tin như:
    • max-age=[seconds]: khoảng thời gian tối đa tính bằng giây mà tài liệu được cache có hiệu lực tính từ thời điểm gửi request
    • private: chỉ ra rằng tài liệu chỉ được cache bởi trình duyệt, không cho phép các share cache như là các proxy
    • public: chỉ ra rằng tài liệu có thể được cache bởi tất cả các thành phần
    • no-cache: tài liệu không được cache mà luôn request lên server

    Cache-Control: max-age=31536000, public
    Cache-Control chỉ được giới thiệu từ HTTP 1.1, tuy nhiên cũng không nên lo lắng về vấn đề này do hiện nay gần như tất cả các server và trình duyệt đều hỗ trợ HTTP 1.1.
    Khi sử dụng cả Expires và Cache-Control thì Cache-Control được ưu tiên.

Weak caching headers

Gồm EtagLast-Modified, còn được gọi là các vadilators. Nếu trình duyệt đã quyết định gửi request tới server, nó sẽ gửi request kèm theo các trường này (lúc này request được gọi là conditional GET request)

  • Etag: Giá trị của trường này có thể dựa trên thời gian chỉnh sửa cuối cùng hay checksum của file. Server sẽ kiểm tra giá trị này với giá trị của file hiện tại trên server, nếu trùng khớp nó chỉ trả về mã 304 Not Modified và trình duyệt sẽ load dữ liệu từ trong cache.

    ETag: "737060cd8c284d8af7ad3082f209582d"

    Etag có nhược điểm là theo mặc định, một file duy nhất khi ở trên các server khác nhau sẽ có Etag khác nhau. Sẽ không sao nếu trang web của bạn chỉ đặt trên một server. Tuy nhiên sẽ là vấn đề nếu website đặt trên nhiều server và được phân tải bởi load-balancer.

  • Last-Modified: tương tự như Etag, nhưng Last-Modified luôn là thời gian chỉnh sửa cuối cùng của file dưới dạng GMT. Last-Modified nằm trong response server trả về, và khi trình duyệt gửi request lên server, nó kèm thêm trường If-Modified-Since với giá trị là Last-Modified cuối cùng nó nhận được.

    Last-Modified: Sat, 8 Mar 2013 07:57:31 GMT

    Khi cả Etag và Last-Modified được sử dụng, server sẽ kiểm tra cả hai trường này, theo nguyên tắc có thể mô tả bằng mã giả như sau:

    if ETagFromServer != ETagOnClient || LastModifiedFromServer != LastModifiedOnClient
       GetFromServer
    else
       GetFromCache
    

Ví dụ: Khi tôi truy cập vào trang tek.eten.vn lần đầu tiên, server sẽ trả về response ứng với request tới file logo.png như sau:

cache1

Ta thấy trường Cache-Control có giá trị max-age là 315360000s = 1 năm, Last-Modified là thời điểm Fri, 21 Feb 2014 08:58:57 GMT
Tôi gõ lại địa chỉ tek.eten.vn một lần nữa

cache2

Trình duyệt hiển thị from cache, nghĩa là nó ko gửi request tới server nữa, do Cache-Control max-age đã được đặt là 1 năm.
Lần này tôi bấm vào Refresh (F5)

cache3

Lúc này trình duyệt đã thực hiện một request lên server kèm theo trường If-Modified-Since có giá trị chính bằng Last-Modified từ response trước đó. Vì giá trị này chưa thay đổi nên server biết rằng trình duyệt đã lưu phiên bản mới nhất của file này, nó chỉ trả về mã 304 Not Modified mà không kèm theo nội dung của file. Trình duyệt dựa vào đó nên chỉ lấy nội dung file từ bộ nhớ cache. Request này được gọi là conditional GET request.

Proxy cache

Cơ chế cache không chỉ được thực hiện tại trình duyệt mà còn tại các public proxy server. Điều này có nghĩa là người dùng lần đầu tiên vào trang web của bạn đã được hưởng lợi: khi một tài liệu được request lần đầu tiên thông qua một proxy server, thì tất cả các user khác ghé thăm trang web thông qua proxy này đều lấy tài liệu tại cache của proxy mà không cần phải truy cập đến server gốc. Điều này cũng gần giống như bạn có một hosting miễn phí đặt gần phía người dùng hơn, giúp cho người dùng truy cập nhanh hơn và giảm thiểu rất nhiều băng thông tới server chính của bạn.
Để cho phép các proxy lưu trữ các tài nguyên của website vào cache, sử dụng Cache-control: public header

Thực hiện

Tổng kết lại, nên thực hiện những việc dưới đây để tối ưu hóa cache:

  • Sử dụng một strong caching header và một weak caching header. Dùng cả hai cho mỗi loại là dư thừa.
    • Nên dùng Cache-Control hơn là Expires do tính linh động của nó. Thời gian hiệu lực nên từ 1 tháng đến tối đa 1 năm đối với những tài nguyên ít thay đổi. Khi thay đổi nội dung của một file và muốn tất cả người dùng đều phải request lại nó, bạn chỉ cần đổi tên riêng file và các liên kết tới file đó.
    • Nên dùng Last-Modified hơn là Etag. Nếu sử dụng Etag, bạn nên cấu hình lại nó.
  • Đặt Cache-Control: public để cho phép cache tại các proxy. Không sử dụng query string với các tài nguyên tĩnh, kiểu như /admin-bar.min.css?ver=3.5.1 do nó sẽ không được các proxy cache lại.

Một số các quy tắc khác:

  • Sử dụng các URL một cách kiên định, không nên có nhiều URL với cùng một nội dung.
  • Chỉ sử dụng POST khi thật cần thiết vì phương thức POST hầu hết không được các bộ nhớ cache hỗ trợ.
  • Không thay đổi nội dung file khi không cần thiết.
  • Chỉ sử dụng cookie với các trang động vì nó cũng không được cache.

Bài tiếp theo tôi sẽ trình bày về tối ưu Round-trip times.

Khi trích dẫn bài viết từ tek.eten.vn, xin vui lòng ghi rõ nguồn. Chúng tôi sẽ rất cảm ơn bạn!