失効済みコンテンツの配信

      Last updated June 04, 2020

    Fastly では、オリジンサーバーに問題が発生している時、またはオリジンサーバーからの新しいコンテンツの取得に長い時間を要している場合に、失効済みコンテンツ(キャッシュしてからTTLに設定された時間が経過したコンテンツ)を配信するよう設定することができます。例えば、Fastly からオリジンサーバーへの接続が失敗する場合、Fastly POP はユーザーのリクエストに対してキャッシュ済みコンテンツの配信を続けます。これらの機能は既定では有効になっていません。

    新しいコンテンツの取得中に古いコンテンツを配信する

    コンテンツによっては生成に時間がかかることがあります。コンテンツはキャッシュされ次第、すばやく配信できるようになりますが、最初にアクセスしようとするユーザーは生成されるのを待たなければなりません。

    the caching time penalty

    キャッシュがまったく存在しないならば、この状況を回避することはできません。一方で、コンテンツはキャッシュされているがその TTL が過ぎている場合、最新コンテンツを取得している間は有効期限切れのコンテンツを配信するよう、Fastly にて設定することが可能です。

    fetching new content in the background

    Mark Nottingham による RFC 5861 HTTP Cache-Control Extensions for Stale Content が定める仕様に基き、Fastly はこの機能を実装しています。この機能は Google の Chrome ブラウザへの導入が検討されています。

    失効済みコンテンツ配信の有効化

    Web コントロールパネルを利用して、初期値の TTL (43200秒間または、12時間) で失効済みコンテンツ配信を有効にするためには、以下の手順に従ってください。もし手動での有効化や失効済みコンテンツ配信の TTL を調整したい場合は、カスタム VCL をご利用ください。

    1. Fastly コントロールパネルにログインし、Configure のリンクをクリックします。
    2. サービスメニューから設定対象のサービスを選択します。
    3. Edit configuration ボタンをクリックし、Clone active を選択すると設定画面が開きます。
    4. Settings のリンクをクリックし、Settings 設定画面を開きます。

      turn on serve stale

    5. Serve stale を クリックすることで自動的に初期値の TTL である43200秒間 (12時間) で失効済みコンテンツ配信を有効に変更します。
    6. Activate ボタンをクリックしてサービスをデプロイします。

    手動による失効済みコンテンツ配信の有効化

    初期値の失効済みコンテンツ配信 TTL とは違う値を設定したい場合には、カスタム VCL を利用することにより手動で設定することができます。この動作を有効にするには、 オリジンサーバーからのレスポンスの Cache-Control もしくは Surrogate-Control ヘッダーに、stale-while-revalidate または stale-if-error ステートメントを追加します。例えば、次のようにします。

    Cache-Control: max-age=600, stale-while-revalidate=30

    その結果、コンテンツを 10 分間キャッシュして、 その 10 分経過後の 30 秒間については、新たなコンテンツが取得されるまで失効済みのコンテンツを提供します。

    同様に、 次のステートメントを指定した場合を考えてみましょう。

    Surrogate-Control: max-age=3600, stale-if-error=86400

    こうすると、キャッシュのコンテンツを 1 時間 (3600 秒) 毎に更新しますが、オリジンがダウンしている場合は期限切れのコンテンツを 1 日間 (86400 秒) 表示します。

    別の方法として VCL 内でこれらの動作を制御することもできます。vcl_fetch に次の変数を設定してください。

    set beresp.stale_while_revalidate = 30s;

    set beresp.stale_if_error = 86400s;

    grace による影響

    stale-if-error は Varnish の変数 grace と同じ動作をします。次の 2 つのステートメントは同等です。

    set beresp.grace = 86400s;

    set beresp.stale_if_error = 86400s;

    ただし、grace のステートメントが VCL 内に存在する場合、grace が優先されるため、Cache-Control または Surrogate-Control レスポンスヘッダー内の stale-if-error のステートメントは無視されます。

    beresp.stale_if_error を指定するだけでは、それがヘッダー内にあっても VCL に記載されていても、失効済みコンテンツの配信は機能しません。失効済みコンテンツの配信を行うには、以下の指示に従ってください。

    エラー発生時に失効済みコンテンツを配信する

    オリジンサーバーがダウンしている状況では、失効済みコンテンツを配信したほうがよいかもしれません。以下で説明する高度な設定方法では、オリジン障害のケース 3 つに対して VCL 内で対応しています。この設定を行うにはカスタム VCL のアップロード機能が有効化されている必要があります。

    Varnish の処理において、オリジン障害には以下 3 つのケースが考えられます。

    下記のカスタム VCL はこれら 3 種類のケースすべてに対応します。オリジンのヘルスステータス異常の場合、失効済みコンテンツの配信のデフォルト動作が stale-if-error により開始されます。オリジン障害の発生からオリジンのヘルスステータスが異常と見なされるまでの間、Varnish は通常 503 エラーを返します。このカスタム VCL では、失効済みキャッシュがある場合はそれを提供し、ない場合はシンセティック・エラーページを返します。このエラーページはカスタマイズ可能です。3 番目のケースを処理するために、vcl_fetch で 5XX エラーの発生を条件に、失効済みコンテンツまたはシンセティック・エラーページを提供します。

    必須ではありませんが、この VCL と一緒にヘルスチェック機能を有効にしてください。ヘルスチェックを有効にしなくともすべての機能が動作しますが、オリジンのタイムアウトを待つため、失効済みコンテンツまたはシンセティック・レスポンスの配信が開始されるまでに待ち時間が発生します。ヘルスチェックを有効にすると、オリジンのヘルスステータスが異常であると把握されるため、待ち時間を省くことができます。

    下記のカスタム VCL には、Fastly 標準のボイラープレートが含まれています。これをご利用のサービスにアップロードする前に、お客様のニーズに合わせて以下の値を修正または削除してください。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    
    sub vcl_recv {
      /* if shielding is enabled, the below code is required */
      if (fastly.ff.visits_this_service != 0) {
        set req.max_stale_while_revalidate = 0s;
      }
    
    #FASTLY recv
    
      if (req.method != "HEAD" && req.method != "GET" && req.method != "FASTLYPURGE") {
        return(pass);
      }
    
      return(lookup);
    }
    
    sub vcl_fetch {
      /* handle 5XX (or any other unwanted status code) */
      if (beresp.status >= 500 && beresp.status < 600) {
    
        /* deliver stale if the object is available */
        if (stale.exists) {
          return(deliver_stale);
        }
    
        if (req.restarts < 1 && (req.method == "GET" || req.method == "HEAD")) {
          restart;
        }
    
        /* else go to vcl_error to deliver a synthetic */
        error beresp.status;
      }
    
      /* set stale_if_error and stale_while_revalidate (customize these values) */
      set beresp.stale_if_error = 86400s;
      set beresp.stale_while_revalidate = 60s;
    
    #FASTLY fetch
    
      if ((beresp.status == 500 || beresp.status == 503) && req.restarts < 1 && (req.method == "GET" || req.method == "HEAD")) {
        restart;
      }
    
      if (req.restarts > 0) {
        set beresp.http.Fastly-Restarts = req.restarts;
      }
    
      if (beresp.http.Set-Cookie) {
        set req.http.Fastly-Cachetype = "SETCOOKIE";
        return(pass);
      }
    
      if (beresp.http.Cache-Control ~ "private") {
        set req.http.Fastly-Cachetype = "PRIVATE";
        return(pass);
      }
    
      /* this code will never be run, commented out for clarity */
      /* if (beresp.status == 500 || beresp.status == 503) {
         set req.http.Fastly-Cachetype = "ERROR";
         set beresp.ttl = 1s;
         set beresp.grace = 5s;
         return(deliver);
      } */
    
      if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
        # keep the ttl here
      } else {
        # apply the default ttl
        set beresp.ttl = 3600s;
      }
    
      return(deliver);
    }
    
    sub vcl_hit {
    #FASTLY hit
    
      if (!obj.cacheable) {
        return(pass);
      }
      return(deliver);
    }
    
    sub vcl_miss {
    #FASTLY miss
      return(fetch);
    }
    
    sub vcl_deliver {
    
    
    #FASTLY deliver
      return(deliver);
    }
    
    sub vcl_error {
    #FASTLY error
    
      /* handle 503s */
      if (obj.status >= 500 && obj.status < 600) {
    
        /* deliver stale object if it is available */
        if (stale.exists) {
          return(deliver_stale);
        }
    
        /* otherwise, return a synthetic */
    
        /* include your HTML response here */
        synthetic {"<!DOCTYPE html><html>Replace this text with the error page you would like to serve to clients if your origin is offline.</html>"};
        return(deliver);
      }
    
    }
    
    sub vcl_pass {
    #FASTLY pass
    }
    
    sub vcl_log {
    #FASTLY log
    }
    

    失効済みコンテンツの配信が正常に機能しない場合のヒント

    Fastly から失効済みコンテンツの配信がうまくいかない場合、以下について確認してください。

    その他の参考資料

    Back to Top