Hãy để véc ni gửi dữ liệu cũ từ bộ đệm trong khi nó đang tìm nạp dữ liệu mới?


8

Tôi đang lưu trữ các trang được tạo động (PHP-FPM, NGINX) và có véc ni trước chúng, điều này hoạt động rất tốt.

Tuy nhiên, khi hết thời gian chờ bộ đệm, tôi thấy điều này:

  • trang yêu cầu khách hàng mới
  • véc ni nhận ra thời gian chờ bộ nhớ cache
  • khách hàng chờ đợi
  • véc ni lấy trang mới từ phụ trợ
  • véc ni cung cấp trang mới cho khách hàng (và cũng được lưu trong bộ nhớ cache cho yêu cầu tiếp theo nhận được ngay lập tức)

Những gì tôi muốn làm là:

  • trang yêu cầu khách hàng
  • véc ni nhận ra thời gian chờ
  • véc ni cung cấp trang cũ cho khách hàng
  • véc ni lấy trang mới từ phụ trợ và đặt nó vào bộ đệm

Trong trường hợp của tôi, đó không phải là trang web mà thông tin lỗi thời là một vấn đề lớn như vậy, đặc biệt là khi chúng ta đang nói về thời gian chờ bộ nhớ cache từ vài phút.

Tuy nhiên, tôi không muốn trừng phạt người dùng xếp hàng chờ đợi và thay vào đó cung cấp một cái gì đó ngay lập tức. Điều đó có thể theo một cách nào đó?

Để minh họa, đây là một đầu ra mẫu của cuộc bao vây chạy 5 phút đối với máy chủ của tôi được cấu hình để lưu trữ trong một phút:

HTTP/1.1,200,  1.97,  12710,/,1,2013-06-24 00:21:06
...
HTTP/1.1,200,  1.88,  12710,/,1,2013-06-24 00:21:20
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:22:08
...
HTTP/1.1,200,  1.89,  12710,/,1,2013-06-24 00:22:22
...
HTTP/1.1,200,  1.94,  12710,/,1,2013-06-24 00:23:10
...
HTTP/1.1,200,  1.91,  12709,/,1,2013-06-24 00:23:23
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:24:12
...

Tôi đã bỏ qua hàng trăm yêu cầu đang chạy 0.02. Nhưng điều đó vẫn khiến tôi lo ngại rằng sẽ có người dùng phải chờ gần 2 giây cho HTML thô của họ.

Chúng ta không thể làm tốt hơn ở đây?

(Tôi đã bắt gặp Varnish gửi trong khi bộ đệm , nghe có vẻ tương tự nhưng không chính xác những gì tôi đang cố gắng làm.)

Giải pháp

Câu trả lời từ Shane Madden có chứa giải pháp nhưng tôi đã không nhận ra ngay lập tức. Có một chi tiết khác tôi không bao gồm trong câu hỏi của mình vì tôi nghĩ nó không liên quan, nhưng thực ra nó là như vậy.

Giải pháp CMS tôi hiện đang sử dụng có trình nghe cơ sở dữ liệu véc ni và do đó có khả năng thông báo véc ni để cấm các trang có nội dung đã thay đổi. Nó đã gửi một PURGEyêu cầu với một số regex để cấm một số trang.

Tóm lại, có hai trường hợp tôi gặp phải những người dùng không may mắn:

  1. véc ni bình thường của một trang hết hạn
  2. người dùng phụ trợ thay đổi nội dung, điều này sẽ gửi một yêu cầu thanh lọc đến véc ni

Trong cả hai trường hợp tôi đều có người dùng "không may mắn". Trong trường hợp thứ hai, nó được giảm bớt bởi thực tế là người dùng phụ trợ thường kiểm tra trang sau khi nó đã được thay đổi; nhưng không nhất thiết

Tuy nhiên, đối với trường hợp thứ hai tôi đã tạo ra một giải pháp (vâng, tôi nhận ra câu hỏi này bắt đầu bằng việc tìm kiếm một câu trả lời cho trường hợp đầu tiên ... câu hỏi được xây dựng kém về phía tôi):

Thay vì gửi yêu cầu thanh lọc, tôi đã sử dụng đề xuất Shanes và điều chỉnh VCL để người nghe cơ sở dữ liệu véc ni của tôi có thể gửi yêu cầu đặc biệt để tìm nạp một trang hash_always_missđược đặt thành true.

Với kiến ​​trúc hiện tại, tôi không thực sự có hứng thú khi thực hiện một yêu cầu không đồng bộ thực sự, nhưng với sự trợ giúp của Làm thế nào để tôi thực hiện một yêu cầu GET không đồng bộ trong PHP? Tôi đã có thể tạo một yêu cầu GET để đánh vecni không chờ trang được tải nhưng đủ tốt để kích hoạt véc ni để lấy trang từ phụ trợ và lưu vào bộ đệm.

Hiệu quả thực tế là người nghe cơ sở dữ liệu đã gửi yêu cầu vecni và trong khi tôi đang thăm dò trang cụ thể thì nó không bao giờ làm cho yêu cầu của tôi "không may mắn" nhưng một khi vecni đã tải trang hoàn toàn từ phần phụ trợ (điều này có thể dao động từ 300ms đến 2 giây) Đột nhiên ở đó.

Tôi vẫn chưa tìm ra giải pháp làm thế nào để tránh những vấn đề tương tự khi hết bình thường, nhưng tôi đoán giải pháp này cũng chính xác như Shane gợi ý: sử dụng wget để kích hoạt hash_always_miss, tôi sẽ phải đủ thông minh để có được danh sách trang tôi phải làm mới.

Câu trả lời:


3

Giải pháp mà tôi đã sử dụng để giải quyết vấn đề này là đảm bảo rằng TTL trên trang không bao giờ có cơ hội hết hạn trước khi được làm mới - buộc máy khách HTTP chạy trên một trong các hệ thống của tôi để tải chậm thay vì máy khách không may mắn yêu cầu.

Trong trường hợp của tôi, điều này liên quan đến wgetmột cron, gửi một tiêu đề đặc biệt để đánh dấu các yêu cầu và cài đặt req.hash_always_missdựa trên điều này, buộc một bản sao mới của nội dung được tìm nạp vào bộ đệm.

acl purge {
    "localhost";
}

sub vcl_recv {
    /* other config here */
    if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) {
        set req.hash_always_miss = true;
    }
    /* ... */
}

Đối với nội dung của bạn, điều này có thể có nghĩa là đặt Varnish TTL thành khoảng 5 phút nhưng có một cron'd wget được cấu hình để thực hiện yêu cầu làm mới bộ đệm mỗi phút.


Tôi nghĩ tôi hiểu ý của bạn. Điều này sẽ làm việc tốt cho một trang, nhưng hàng ngàn khác? Không thể sử dụng cron / wget trên thang đo đó.
đánh dấu

Về mặt bản chất, bạn phải khai báo ít nhất những trang bạn muốn giữ hiện tại trong bộ đệm. Đưa ra danh sách này, không có lý do gì để quên trong một kịch bản cron không thể giúp bạn.
Falcon Momot

Tôi nghĩ đó là thách thức với "phương pháp tiếp cận bên ngoài" này. Cuối cùng tôi cần phải ngồi xuống và đưa ra quyết định và thực hiện điều này cho mỗi trang. Không có cách nào để nói vecni: "ttl đã hết? Lấy phiên bản mới nhưng cho đến khi điều đó xảy ra phục vụ phiên bản cũ" ...? Hừm.
đánh dấu

4

@BIÊN TẬP:

Chỉ cần nhanh chóng cho bạn biết rằng tính năng này dường như chỉ mới được triển khai trong phiên bản mới nhất trong nhánh chính, rất có thể phiên bản của bạn có thể không hỗ trợ xác thực / ví dụ tôi đã đăng sẽ phục vụ 9999/10000 yêu cầu với một bugger nghèo vẫn phải chờ yêu cầu hoàn thành vào phần phụ trợ (Vẫn tốt hơn không có gì;) ...


Chà, tôi không chắc chắn 100% lý do tại sao các bình luận trước đó nói rằng nó không hoạt động nhưng theo: https://www.varnish-software.com/static/book/Saving_a_Vquest.html

  • req.grace - xác định thời gian một đối tượng có thể quá hạn để Varnish vẫn xem xét nó cho chế độ ân sủng.
  • beresp.grace - xác định thời gian vượt qua beresp.ttl-time Varnish sẽ giữ một đối tượng.
  • req.grace - thường được sửa đổi trong vcl_recv dựa trên trạng thái của phụ trợ.

Tôi hiện đang sử dụng cấu hình như những gì hướng dẫn sử dụng nói và nó hoạt động tốt ... Đây là một đoạn của tệp vcl của tôi ...

sub vcl_recv {
    # Cache rules above here...
    if (req.backend.healthy) {
        set req.grace = 30d;
    } else {
        set req.grace = 300d;
    }
}

sub vcl_fetch {
    # Fetch rules above here ...

    # If backend returns 500 error then boost the cache grace period...
    if (beresp.status == 500) {
        set beresp.grace = 10h;
        return (restart);
    }

    # How long carnish should keep the objects in cache..
    set beresp.grace = 1h;

    # Actual TTL of cache - If an object is older than this an update will be triggered to the backend server :)
    set beresp.ttl = 1m;
}

Lưu ý rằng nếu bạn muốn cung cấp thời gian ân hạn phản hồi phụ trợ dài hơn (đối với 500 lỗi như trong cấu hình của tôi), bạn sẽ cần phải thiết lập thăm dò phụ trợ ... Đây là bản sao của thăm dò phụ trợ của tôi ..

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = { 
        .url = "/nginx-status";
        .timeout = 500 ms; 
        .interval = 3s; 
        .window = 10;
        .threshold = 4;
    }
}

Điều này vẫn còn hiệu lực cho vcl 4.0?
Gadelkareem

0

Trong Varnish 3, điều này đạt được thông qua "Chế độ ân sủng". Theo hướng dẫn [1], bạn phải thêm logic sau:

sub vcl_fetch {
  set beresp.grace = 30m;
} // Makes objects to be cached/stored 30 min beyond its max-age/ttl

sub vcl_recv {
  set req.grace = 60s;
} // Allows varnish to serve objects which expired within last minute.

[1] https://www.varnish-cache.org/docs/3.0/tutorial/handling_mvdehaving_servers.html#grace-mode


Điều này sẽ không đạt được mục tiêu của OP, một khách hàng sẽ vẫn bị trì hoãn chờ đợi nội dung được tải xuống từ phần phụ trợ, mặc dù các khách hàng khác đằng sau đó sẽ được phục vụ kết quả ân sủng cũ. "Khi hết hạn, máy khách đầu tiên yêu cầu nội dung sẽ bị kẹt trong 15 giây, trong khi máy khách thứ hai sẽ nhận được bản sao được tô điểm." - var Vec-software.com/static/book/Saving_a numquest.html
Pax

Xin lỗi, tôi đã không nhận ra nó thực sự hoạt động như thế nào với yêu cầu hết hạn đầu tiên.
NITEMAN

Có lẽ mục tiêu mong muốn có thể đạt được với một số ttl cheat & nội tuyến C để thực hiện "yêu cầu nền"
NITEMAN
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.