[Nginx] Lỗi trắng trang website khi xài Nginx + FastCGI Caching

Chào các bạn .
Trong bài viết này mình sẽ nói đến 1 vấn đề mà mình vừa mắc phải và cũng khá phổ biến đó là : lỗi trắng trang khi truy cập Website với hệ thống Server/VPS sử dụng Nginx + FastCGI Caching + PHP-FPM.
Trong trường hợp trên mình có cấu hình Nginx Caching với cơ chế FastCGI Caching nhằm cache lại nội dung .html được xử lý từ PHP backend tăng hiệu suất phục vụ người dùng thì xuất hiện một trường hợp đó là đôi khi gặp phải lỗi trắng trang hoàn toàn homepage hoặc trang link khác nếu có xảy ra.
Cấu hình Nginx Caching :
fastcgi_cache_path /dev/shm/nginx-cache/ levels=1:2 keys_zone=CACHE:50m inactive=120m;
fastcgi_cache_key "$scheme$host$request_uri";

server {
      ....
      location ~ \.php$
        {
            fastcgi_pass   unix:/var/lib/php/php.sock;
            if (!-f $realpath_root$fastcgi_script_name) {
                   return 404;
            }
            include /etc/nginx/conf.d/fastcgi-buffer.conf;
            fastcgi_cache CACHE;
            fastcgi_cache_valid 200 60m;
            fastcgi_cache_bypass $skip_cache $is_mobile;
            fastcgi_no_cache $skip_cache $is_mobile;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
            include        fastcgi_params;
        }
}
Thời gian debug sẽ khá là không có kết quả khi :
– PHP FPM không hề xuất ra bất cứ lỗi log nào.
– Nginx error log, cũng không hề trả về lỗi log giữa frontend và backend php-fpm.
– Nginx normal log, thì trả về status code 200 bình thường không trả về log status code khác.
Nhưng có vấn đề thế này, khi view các log Nginx status code 200 vào thời điểm đó và 200 vào thời điểm bình thường.
Log lỗi lúc trắng trang :
xxx.xxx.xxx.xxx - - [09/Jan/2016:09:29:35 +0700] "HEAD / HTTP/1.1" 200 0 "-" "Mozilla/5.0+(compatible; UptimeRobot/2.0; http://www.uptimerobot.com/)" "-"
xxx.xxx.xxx.xxx - - [09/Jan/2016:09:32:09 +0700] "GET / HTTP/1.1" 200 31 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36" "-"
Log bình thường :
xxx.xxx.xxx.xxx - - [09/Jan/2016:08:07:03 +0700] "GET / HTTP/1.1" 200 36959 "-" "Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12F70 Safari/600.1.4" "-"
Lúc này ta sẽ thấy phần GET ở log bình thường trả về 36959 bytes dung lượng gói tin, còn GET log lỗi thì chỉ có 31 bytes tức chỉ có phần bytes thông tin header chứ không có dung lượng body gói tin HTTP response trả về người dùng.
Sau một hồi review thì mình phát hiện ra các gói tin HEAD trong log và cũng đã phần nào đoán được nguyên nhân.
Với cơ chế HEAD, thì khi truy xuất Webserver sẽ gửi request cho PHP xử lý, nhưng HEAD chỉ yêu cầu thông tin header chứ không cần nội dung body trả về nên khi PHP xử lý xong sẽ không trả về nội dung body của đường dẫn truy xuất. Dẫn đến tình trạng cache .html trắng trang và các log thông báo cũng hoàn toàn không xem đó là lỗi.
Ở đây bạn phải hiểu cơ chế caching Nginx rồi sẽ tiện hơn. Mình sẽ có bài viết về Nginx Caching sau.

 

Vậy cách thức xử lý của chúng ta sẽ là 2 hướng:
1. Thay đổi giá trị “cache key” hiện tại của Nginx Caching
– Do mình cấu hình cache_key là “$scheme$host$request_uri” nên lúc cache sẽ không cộng thêm giá trị string request method HEAD hay GET rồi băm MD5 ra lưu directory phân nhánh. Nên khi cache hết hạn sử dụng, thì gặp gói tin HEAD sẽ dẫn đến tình trạng trên.
– Vậy chúng ta sẽ phân biệt lưu caching thêm cho HEAD hoặc GET ở phần cache_key bằng cách thêm giá trị $request_method” vào cache_key.
 
fastcgi_cache_key "$scheme$request_method$host$request_uri";
Nhược điểm:
– Cache sẽ lưu gấp đôi nếu nhiều tool xài HEAD đẩy vào các link. Điều này không hay, nên không khuyến khích.
2. Đưa Request Method HEAD vào danh sách đối tượng không lưu cache
– Với cách này, khi Nginx tiếp nhận 1 request có method là HEAD thì sẽ không tiến hành lưu cache đối với các request dạng này.
Cấu hình cho HEAD vào list không cache :
if ($request_method = HEAD) {
            set $skip_cache 1;
}
Cấu hình đầy đủ :
fastcgi_cache_path /dev/shm/nginx-cache/ levels=1:2 keys_zone=CACHE:50m inactive=120m;
fastcgi_cache_key "$scheme$host$request_uri";

server {
      ....
      set $skip_cache 0;

        if ($request_method = POST) {
            set $skip_cache 1;
        }
        if ($request_method = HEAD) {
            set $skip_cache 1;
        }
      ....
location ~ \.php$
        {
            fastcgi_pass   unix:/var/lib/php/php.sock;
            if (!-f $realpath_root$fastcgi_script_name) {
                   return 404;
            }
            include /etc/nginx/conf.d/fastcgi-buffer.conf;
            fastcgi_cache CACHE;
            fastcgi_cache_valid 200 60m;
            fastcgi_cache_bypass $skip_cache $is_mobile;
            fastcgi_no_cache $skip_cache $is_mobile;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  /var/www/html/$fastcgi_script_name;
            include        fastcgi_params;
        }
}
Sau đó các bạn xoá cache Nginx và truy cập lại bình thường. Chúc các bạn thành công.
Previous article[CSF] Lỗi “Binary location for [HOST] [/usr/bin/host] in /etc/csf/csf.conf is either incorrect”
Next article[DirectAdmin] Lỗi “warning : saved filesize is less than uploaded filesize. check quota” trên DA
Bạn đang theo dõi website "https://cuongquach.com/" nơi lưu trữ những kiến thức tổng hợp và chia sẻ cá nhân về Quản Trị Hệ Thống Dịch Vụ & Mạng, được xây dựng lại dưới nền tảng kinh nghiệm của bản thân mình, Quách Chí Cường. Hy vọng bạn sẽ thích nơi này !