web-dev-qa-db-ja.com

新しいデータをフェッチしている間に、ワニスがキャッシュから古いデータを送信できるようにしますか?

動的に生成されたページ(PHP-FPM、NGINX)をキャッシュし、その前にワニスを付けています。これは非常にうまく機能します。

ただし、キャッシュタイムアウトに達すると、次のようになります。

  • 新しいクライアントリクエストページ
  • ワニスはキャッシュタイムアウトを認識します
  • クライアントが待機する
  • ワニスはバックエンドから新しいページを取得します
  • varnishは新しいページをクライアントに配信します(また、すぐに取得する次のリクエストのためにページもキャッシュされます)

私がしたいのは:

  • クライアントリクエストページ
  • ワニスはタイムアウトを認識します
  • ニスは古いページをクライアントに配信します
  • ワニスはバックエンドから新しいページをフェッチしてキャッシュに入れます

私の場合、特に数分からのキャッシュタイムアウトについて話しているときではなく、古い情報が非常に大きな問題を抱えているサイトではありません。

しかし、私はユーザーを罰せずに並んで待って、すぐに何かを届けたいとは思いません。それは何らかの方法で可能ですか?

例として、1分間キャッシュするように構成された私のサーバーに対してsiegeを5分間実行したサンプル出力を次に示します。

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
...

0.02で実行されている何百ものリクエストを省略しました。しかし、未加工のHTMLを2秒近く待たなければならないユーザーがいるのではないかと、私はまだ懸念しています。

ここでもっと上手くやれないの?

(私は Varnish send while cache に遭遇しました、それは同じように聞こえましたが、正確に私がやろうとしていることではありません。)

ソリューション

Shane Maddenの回答には解決策が含まれていましたが、すぐにはわかりませんでした。関連性がないと思ったので質問に含めなかった詳細がもう1つありましたが、実際はそうです。

私が現在使用しているCMSソリューションには、ニスデータベースリスナーがあり、コンテンツが変更されたページを禁止するようにニスに通知する機能があります。特定のページを禁止する正規表現を含むPURGEリクエストを送信しました。

要約すると、私が不運なユーザーを獲得した2つのケースがあります。

  1. 通常のニスTTLページの有効期限が切れています
  2. バックエンドユーザーがコンテンツを変更すると、これによりニスにパージリクエストが送信されます

どちらの場合も、「不運な」ユーザーがいます。 2番目のケースでは、バックエンドユーザーは通常、ページが変更された後にページをチェックするという事実によって緩和されます。必ずしもそうではありません。

それにもかかわらず、2番目のケースでは解決策を作成しました(そうです、この質問は最初のケースの答えを探すことから始まりました...私の側では不十分に定式化された質問です)。

パージリクエストを送信する代わりに、Shanesの提案を使用してVCLを調整し、ワニスデータベースリスナーがhash_always_misstrueに設定してページをフェッチする特別なリクエストを送信できるようにしました。

現在のアーキテクチャでは、実際の非同期リクエストを実行する余裕は本当にありませんが、 の助けを借りて、PHPで非同期GETリクエストを作成するにはどうすればよいですか? ワニスへのGETリクエストを作成します。これは、ページが読み込まれるのを待たずに、ワニスをトリガーしてバックエンドからページをフェッチしてキャッシュするのに十分です。

正味の影響は、データベースリスナーがニスにリクエストを送信し、特定のページをポーリングしている間はリクエストが「不運」になることはありませんでしたが、ニスがバックエンドからページを完全にフェッチすると(300ミリ秒から2秒の範囲になる可能性があります)。突然そこにいた。

私はまだ、通常のTTLがなくなったときに同じ問題を回避する方法の解決策を見つける必要がありますが、解決策はShaneの提案とまったく同じだと思います。wgetを使用してhash_always_missをトリガーして、更新しなければならないページのリストを取得できるほど賢くする必要があります。

8
mark

この問題を解決するために使用した解決策は、ページのTTLが更新される前に期限切れになる可能性がないことを確認することです。私のシステムの1つで実行されているHTTPクライアントに、不運なクライアント要求の代わりに遅いロードを取得します。

私の場合、これにはcronでのwget、リクエストにマークを付けるための特別なヘッダーの送信、これに基づくreq.hash_always_missの設定が含まれ、コンテンツの新しいコピーが強制的にキャッシュにフェッチされます。

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;
    }
    /* ... */
}

コンテンツの場合、これはVarnish TTL=を5分程度に設定することを意味しますが、毎分キャッシュ更新リクエストを行うようにcron'd wgetを構成する必要があります。

3
Shane Madden

@編集:

この機能がマスターブランチの最新バージョンに実装されたばかりであるように思われることを簡単にお知らせします。バージョンがtrueをサポートしていない可能性がありますstale-while-revalidateまだ/私が投稿した例では、バックエンドでリクエストが完了するのをまだ待たなければならない1人の貧しいバガーが9999/10000リクエストを処理します(それでも何もないよりはましです;)...


さて、私は以前のコメントがそれが機能していないと言っている理由を100%確信していませんが、それによると https://www.varnish-software.com/static/book/Saving_a_request.html

  • req.grace-Varnishがオブジェクトを猶予モードと見なすのにオブジェクトがどれだけ遅れるかを定義します。
  • beresp.grace-beresp.ttl-time Varnishがオブジェクトを保持する期間を定義します。
  • req.grace-バックエンドの状態に基づいてvcl_recvでしばしば変更されます。

私は現在、マニュアルに書かれているような設定を使用しており、正常に動作しています...これは私のvclファイルのスニペットです...

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;
}

より長いバックエンド応答猶予期間を提供したい場合(私の構成のように500エラーの場合)、バックエンドプローブをセットアップする必要があることに注意してください...これが私のバックエンドプローブのコピーです。

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

Varnish 3では、これは「猶予モード」によって実現されます。マニュアル[1]によれば、次のロジックを追加する必要があります:

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_misbehaving_servers.html#grace-mode

0
NITEMAN