失効済みコンテンツの配信
Last updated December 07, 2020
Fastly では、オリジンサーバーに問題が発生している時、またはオリジンサーバーからの新しいコンテンツの取得に長い時間を要している場合に、失効済みコンテンツ(キャッシュしてからTTLに設定された時間が経過したコンテンツ)を配信するよう設定することができます。例えば、Fastly からオリジンサーバーへの接続が失敗する場合、Fastly POP はユーザーのリクエストに対してキャッシュ済みコンテンツの配信を続けます。これらの機能は既定では有効になっていません。
新しいコンテンツの取得中に古いコンテンツを配信する
コンテンツによっては生成に時間がかかることがあります。コンテンツはキャッシュされ次第、すばやく配信できるようになりますが、最初にアクセスしようとするユーザーは生成されるのを待たなければなりません。
キャッシュがまったく存在しないならば、この状況を回避することはできません。一方で、コンテンツはキャッシュされているがその TTL が過ぎている場合、最新コンテンツを取得している間は有効期限切れのコンテンツを配信するよう、Fastly にて設定することが可能です。
Mark Nottingham による RFC 5861 HTTP Cache-Control Extensions for Stale Content が定める仕様に基き、Fastly はこの機能を実装しています。この機能は Google の Chrome ブラウザへの導入が検討されています。
失効済みコンテンツ配信の有効化
注意: カスタム VCL を利用してこの機能を有効にしている場合は、Web コントロールパネルでこの機能を追加することにより、失効済みコンテンツに異なる TTL が設定されます。これを回避するため、Web コントロールパネルでこの機能を有効化する前に stale-if-error
のステートメントをカスタム VCL から削除してください。
Web コントロールパネルを利用して、初期値の TTL (43200秒間または、12時間) で失効済みコンテンツ配信を有効にするためには、以下の手順に従ってください。もし手動での有効化や失効済みコンテンツ配信の TTL を調整したい場合は、カスタム VCL をご利用ください。
- Fastly コントロールパネルにログインし、Configure のリンクをクリックします。
- サービスメニューから設定対象のサービスを選択します。
- Edit configuration ボタンをクリックし、Clone active を選択すると設定画面が開きます。
-
Settings のリンクをクリックし、Settings 設定画面を開きます。
- Serve stale を クリックすることで自動的に初期値の TTL である43200秒間 (12時間) で失効済みコンテンツ配信を有効に変更します。
- 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 つのケースが考えられます。
- ヘルスチェック失敗により、オリジンが unhealthy (ヘルスステータス異常) と見なされる
- Varnish からオリジンへの接続失敗により、503 エラーが発生する
- オリジンからの HTTP レスポンスが、ユーザーへの配信に適さない内容である (例:503 エラー)
下記のカスタム VCL はこれら 3 種類のケースすべてに対応します。オリジンのヘルスステータス異常の場合、失効済みコンテンツの配信のデフォルト動作が stale-if-error
により開始されます。オリジン障害の発生からオリジンのヘルスステータスが異常と見なされるまでの間、Varnish は通常 503 エラーを返します。このカスタム VCL では、失効済みキャッシュがある場合はそれを提供し、ない場合はシンセティック・エラーページを返します。このエラーページはカスタマイズ可能です。3 番目のケースを処理するために、vcl_fetch
で 5XX エラーの発生を条件に、失効済みコンテンツまたはシンセティック・エラーページを提供します。
警告: 503 エラーが発生している場合、キャッシュされたコンテンツに対する全コンテンツのパージの実行は避けてください。全コンテンツのパージを行うと stale-if-error が機能しなくなるため、オリジンサーバーへのリクエスト数が増加します。その結果、503 エラーがさらに増える可能性があります。
必須ではありませんが、この VCL と一緒にヘルスチェック機能を有効にしてください。ヘルスチェックを有効にしなくともすべての機能が動作しますが、オリジンのタイムアウトを待つため、失効済みコンテンツまたはシンセティック・レスポンスの配信が開始されるまでに待ち時間が発生します。ヘルスチェックを有効にすると、オリジンのヘルスステータスが異常であると把握されるため、待ち時間を省くことができます。
下記のカスタム VCL には、Fastly 標準のボイラープレートが含まれています。これをご利用のサービスにアップロードする前に、お客様のニーズに合わせて以下の値を修正または削除してください。
if (beresp.status >= 500 && beresp.status < 600)
には、失効済みコンテンツやシンセティックページを提供すべき HTTP レスポンスコードを含めるように変更します。-
set beresp.stale_if_error = 86400s;
は、失効済みコンテンツを提供する期間を制御するもので、お客様の構成に応じて適切な値を設定してください。 オリジンからの Surrogate-Control または Cache-Control ヘッダーにてstale_if_error
を送信する場合は、 この行全体を削除してください。 set beresp.stale_while_revalidate = 60s;
は、 キャッシュに対するstale_while_revalidate
機能の有効期間を制御するもので、お客様の構成に応じて適切な値を設定してください。この機能により、Varnish はキャッシュミス時に期限切れコンテンツを提供しながら、 そのバックグラウンドでオリジンから最新版のオブジェクトを取得します。結果的に、TTL が短いオブジェクトや、キャッシュミス全般に対して、パフォーマンスを大幅に向上できる可能性があります。stale_while_revalidate
はstale_if_error
より優先されることに注意してください。 つまり、キャッシュミス時点でオブジェクトが、stale_while_revalidate
の基準を満たしていれば、stale_if_error
は無視されます。 オリジンからの Surrogate-Control または Cache-Control ヘッダーにてstale_while_revalidate
を送信する場合は、この行全体を削除してください。synthetic {"<!DOCTYPE html>Your HTML!</html>"};
は、有効期限切れバージョンのオブジェクトが利用できない場合に Varnish が返すシンセティックレスポンスで、お客様の構成に応じて適切に設定してください。ここには、HTML や CSS、JS を埋め込むことができます。外部 CSS および JS ドキュメントを参照する際には、注意が必要です。オリジンがオフラインの場合、それらも利用できない可能性があります。
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 から失効済みコンテンツの配信がうまくいかない場合、以下について確認してください。
- キャッシュ: 失効済みコンテンツはキャッシュ可能な場合にのみ利用可能です。
- VCL:
req.hash_always_miss
またはreq.hash_ignore_busy
をtrue
に設定すると、stale-while-revalidate
の効果が無効になります。 - オリジンシールド: オリジンシールドを有効化していない場合、ある POP からエラー発生時の失効済みコンテンツの配信は、当該 POP 経由でそのキャッシュ可能コンテンツを配信した実績がある場合のみ、可能です。失効済みコンテンツがエラー発生時にキャッシュされている確率を高めるため、オリジンシールドの有効化を推奨します。オリジンシールドはまた、全コンテンツのパージ実行後に速やかにコンテンツをキャッシュさせるためにも効果的です。
- リクエスト: サイトへのトラフィックの増加に伴って、(オリジンシールド使わない場合でも) 失効済みのキャッシュが存在する確率が高くなります。人気のあるコンテンツならば、複数の POP においてキャッシュされることもあります。
- Least Recently Used (LRU): Fastly は LRU リスト(参照頻度に基づくキャッシュ済みコンテンツのリスト)によりキャッシュ内のファイルを管理します。このため、TTL (time to live: キャッシュ保持時間) を長く設定しても、その TTL の期間中キャッシュが常に保持されることは保証されません。キャッシュの保持と削除は、ファイルに対するリクエストの頻度、TTL の値、ファイルの配信元となるPOP など、多くの要因に依存します。一例ですが、3700 秒以上の TTL のファイルがディスクへ保管される一方で、3700 秒未満の TTL の場合はメモリーのみに保管されます。可能であれば 3700 秒以上の TTL の設定を推奨します。
- パージ: パージの際は、可能な限りソフトパージを実行してください。ソフトパージを使うと、Fastly のキャッシュサーバーからファイルを消去する代わりに、そのコンテンツを失効させることができます。ソフトパージが不可能ならば、全コンテンツのパージをできる限り避けて、URL によるパージかキーによるパージの活用を推奨します。