Giới thiệu
Chúng ta đều biết rằng performance của các applications và website là yếu tố rất quan trọng trong môi trường internet hiện tại. Tuy nhiên, quá trình làm cho applications và website của bạn hoạt động tốt hơn, không phải lúc nào cũng dễ dàng. Chất lượng mã nguồn và cơ sở hạ tầng tất nhiên là rất quan trọng. Nhưng trong nhiều trường hợp, bạn có thể cải thiện trải nghiệm người dùng cuối của ứng dụng bằng cách tập trung vào một số kỹ thuật rất cơ bản như caching. Bài viết này sẽ giới thiệu và hướng dẫn bạn sử dụng kỹ thuật caching trên Nginx để nâng cao performance hệ thống và trải nghiệm người dùng tốt hơn.
Khái niệm Caching
Chúng ta xét đến ví dụ về quá trình dữ liệu được trao đổi giữa client và server với các phản hồi HTTP như sau. Hãy bắt đầu với tình huống không có bộ nhớ cache, trông giống như thế này.
Người dùng thực hiện một request cho ứng dụng và nhận được respone.
Thêm cache vào kịch bản này là một cách đơn giản để cải thiện hiệu suất, tính đáp ứng cao hơn. Nó hoạt động bằng cách lưu các respone từ máy chủ hoặc ứng dụng vào ram hoặc disk.
Hãy xem xét tình huống đơn giản này. Máy khách thực hiện một request cho App như trong ví dụ trước nhưng lần này đi qua cache.
App trả về respone đến máy khách nhưng nó cũng lưu respone trên disk.
Lần tới, người dùng thực hiện cùng một request và hệ thống kiểm tra cache có respone tương ứng không.
Và nếu đó là trường hợp request đã được thực hiện trước đó và hệ thống có lưu respone đã xư lý, nó sẽ phản hồi ngay lập tức cho người dùng, bằng cách phục vụ nội dung được lưu trong bộ nhớ cache này.
Lưu ý là đối với request được máy chủ phục vụ trực tiếp từ cache mà không cần phải thông qua App.
Caching sẽ thêm phức tạp cho hệ thống nhưng nó đi kèm với những lợi ích tuyệt vời :
- Cải thiện hiệu suất trang web – các yêu cầu không phải trải qua toàn bộ quá trình xử lý từ đầu.
- Tăng khản năng chịu tải – bằng cách giảm tải trên các máy chủ gốc khi không phải xử lý nhiều request giống nhau.
- Mang lại tính khả dụng cao hơn – bằng cách phục vụ nội dung cũ(được cache) khi máy chủ không hoạt động
Cache với Nginx
Nginx là một máy chủ HTTP và thật tuyệt vời khi phục vụ các tệp tĩnh và yêu cầu ủy quyền. Do tính chất không đồng bộ của nó, nó nổi bật với việc sử dụng tài nguyên trọng lượng nhẹ.
Cache trên Nginx hỗ trợ cho
- Máy chủ HTTP
- FastCGI
- uwsgi
- SCGI
Để bật cơ chế caching, ta cần phải thêm chỉ thị proxy_cache_path trong block http { }
http { ... proxy_cache_path /data/nginx/cache keys_zone=one:10m; }
để kích hoạt chúng ta cần cấu hình thêm chỉ thị cache proxy_cache
http { ... proxy_cache_path /data/nginx/cache keys_zone=one:10m; server { proxy_cache mycache; location / { proxy_pass http://localhost:8000; } } }
Nginx quản lý cache như thế nào
Có 2 tiến trình của Nginx quản lý bộ nhớ cache(cache load):
- Cache manager: được kích hoạt định kỳ để kiểm tra trạng thái của cache. Nếu kích thước của cache vượt quá giá trị max_size thì cache manager sẽ xóa bỏ phần dữ liệu ít được truy cập nhất.
- Cache loader: tiến trình này chỉ hoạt động duy nhất một lần ngay khi Nginx khởi động. Nó có nhiệm vụ nạp metadata của dữ liệu được cache trước đó vào bộ nhớ chung. Nạp lại toàn bộ cache khi nginx khởi động sẽ làm chậm Nginx, để giảm thiểu việc này, ta có thể cấu hình load cache tuần tự theo thời gian, mỗi lần sẽ load một phần cache lên.
Các thông số để cấu hình việc cache load trong nginx
- loader_threshold – Thời gian mỗi lần nạp cache (miliseconds)
- loader_files – Số lượng file tối đa nginx nạp trong mỗi lần (mặc định là 100).
- loader_sleeps – Thời gian giữa mỗi lần nạp cache (miliseconds), mặc định là 50ms.
Trong ví dụ sau, nginx sẽ lặp lại việc load cache mỗi 300 mili giây hoặc cho đến khi 200 mục được tải:
proxy_cache_path /data/nginx/cache keys_zone=one:10m loader_threshold=300 loader_files=200;
What/When to cache?
Theo mặc định, Nginx chỉ lưu trữ các yêu cầu GET và HEAD. Bạn có thể thay đổi điều này bằng chỉ thị proxy_cache_methods
proxy_cache_methods GET HEAD POST;
Bạn cũng có thể hướng dẫn Nginx lưu trữ phản hồi chỉ sau khi được yêu cầu ít nhất 5 lần.
proxy_cache_min_uses 5;
Điều này sẽ hữu ích trong trường hợp bạn có nhiều nội dung, nhưng bạn chỉ muốn lưu trữ những yêu cầu thực sự phổ biến.
Nginx có thể tiết kiệm băng thông disk I/O. Bằng cách tôn trọng các cache headers và mã http 304, các phản hồi không được sửa đổi, Nginx sẽ không tải lại nội dung nếu chỉ thị sau được bật:
proxy_cache_revalidate on;
Cách chỉ định những yêu cầu để lưu trữ
Với Nginx, chúng tôi không giới hạn bộ nhớ cache mọi thứ theo cùng một quy tắc. Thay vào đó, chúng ta có thể cho Nginx biết thông tin nào sẽ được sử dụng để tạo khóa băm. Và chúng tôi có thể làm điều đó ở cấp độ http, máy chủ hoặc vị trí. Đây là hai ví dụ:
proxy_cache_key "$host$request_uri$cookie_user";
proxy_cache_key "$scheme$proxy_host$uri$is_args$args";
Hoăc cũng có thể nói với Nginx, trong những điều kiện nào thì yêu cầu không nên được lưu trữ trong bộ đệm.
proxy_no_cache $http_pragma $http_authorization $cookie_nocache $arg_nocache;
How long to cache?
Có một vài chỉ thị đơn giản cho Nginx biết thời gian lưu trữ các phản hồi của một loại nhất định:
proxy_cache_valid any 1m; proxy_cache_valid 200 302 10m;
Nhưng chủ yếu là các header của máy chủ gốc xác định khả năng lưu trữ của nội dung:
- Expires
- Cache-Control
- X-Accel-Expires – Nginx special header.
Overrides other headers. Used when you need to serve different headers to the client.
Mức độ ưu tiên của các tùy chọn được đề cập được trình bày trên biểu đồ bên dưới, với mức độ ưu tiên mạnh nhất ở trên cùng:
Một số chỉ thị khác
Các tùy chọn sau đây thêm rất nhiều vào các yếu tố sẵn có. Nó cho phép Nginx phục vụ nội dung cũ (cũ, hết hạn) khi phản hồi của ứng dụng hết thời gian hoặc trả về mã trạng thái 50x:
proxy_cache_use_stale error timeout;
Với proxy_cache_lock được bật, nếu nhiều máy khách yêu cầu một tệp không có trong bộ đệm (MISS), chỉ những yêu cầu đầu tiên trong số đó mới được phép thông qua máy chủ gốc. Các yêu cầu còn lại chờ yêu cầu đó được thỏa mãn và sau đó kéo tệp từ bộ đệm. Nếu không bật proxy_cache_lock, tất cả các yêu cầu dẫn đến lỗi bộ nhớ cache sẽ chuyển thẳng đến máy chủ gốc.
proxy_cache_lock on;
Purge cache.
Chúng ta sẽ cấu hình HTTP PURGE để thực hiện xóa theo URLs
- Trong block http{} chúng ta tạo ra một biến mới, ví dụ: $ purge_method, phụ thuộc vào biến $ request_method:
http { ... map $request_method $purge_method { PURGE 1; default 0; } }
- Trong block location{} nơi cache được định cấu hình, hãy thêm proxy_cache_purge để chỉ định một điều kiện cho các yêu cầu xóa bộ đệm. Trong ví dụ này, đó là $ purge_method được cấu hình ở bước trước:
server { listen 80; server_name www.example.com; location / { proxy_pass https://localhost:8002; proxy_cache mycache; proxy_cache_purge $purge_method; } }
Gủi lệnh Purge cache
Khi chỉ thị proxy_cache_purge được định cấu hình, bạn cần gửi yêu cầu purge cache để xóa cache. Bạn có thể đưa ra các yêu cầu purge bằng nhiều công cụ, bao gồm lệnh curl như trong ví dụ này:
$ curl -X PURGE -D – "https://www.example.com/*" HTTP/1.1 204 No Content Server: nginx/1.15.0 Date: Sat, 19 May 2018 16:33:04 GMT Connection: keep-alive
Trong ví dụ này, các tài nguyên có một phần URL chung (được chỉ định bởi ký tự đại diện dấu hoa thị) sẽ bị xóa. Tuy nhiên, các mục cache như vậy không bị xóa hoàn toàn khỏi bộ cache: chúng vẫn còn trên nơi lưu trữ cho đến khi chúng bị xóa vì không hoạt động ( chỉ thị proxy_cache_path được cấu hình thêm tham số inactive ) hoặc bởi bộ lọc bộ đệm (được bật với tham số purger trong cấu hình proxy_cache_path) hoặc khách hàng cố gắng truy cập chúng.
Hạn chế quyền truy cập vào tính năng purger cache
Cấu hình sau sẽ chỉ cho IP nhất định được phép chạy lệnh purge cache
geo $purge_allowed { default 0; # deny from other 10.0.0.1 1; # allow from localhost 192.168.0.0/24 1; # allow from 10.0.0.0/24 } map $request_method $purge_method { PURGE $purge_allowed; default 0; }
Xóa hoàn toàn các nội dung cache khỏi bộ nhớ cache
Để xóa hoàn toàn nội dung cache bạn có thể thêm chỉ thị purger trong phần cấu hình proxy_cache_path
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on;
Dưới đây là 1 ví vụ về purge cache
http { ... proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m purger=on; map $request_method $purge_method { PURGE 1; default 0; } server { listen 80; server_name www.example.com; location / { proxy_pass https://localhost:8002; proxy_cache mycache; proxy_cache_purge $purge_method; } } geo $purge_allowed { default 0; 10.0.0.1 1; 192.168.0.0/24 1; } map $request_method $purge_method { PURGE $purge_allowed; default 0; } }