VarnishでランダムなTTLを設定

varnish-logoVarnish でキャッシュされていないページにクライアントからアクセスがあると、HTMLだけでなく、そのページを構成する画像その他のリソースも当然一緒にリクエストされる。
もし、要求されたページの多くがキャッシュされておらず、同じTTLが設定されていたとすると、expire 後のアクセスでは同時に各リソースがオリジンサーバにリクエストされてしまう。

同僚が「ttlをランダムにしたいよねー」と(物理的に)つぶやいていたので忙しい同僚に代わって調べた。

環境

  • OS Ubuntu 12.04 64 bit
  • Varnish 3.0.4(公式レポジトリ提供)
  • nginx/1.1.19(画像をサーブしているだけなので何でもよい)

Varnishで乱数を生成

Varnish 標準の VMOD である vmod_std(VCL用ユーティリティ関数群) に含まれる rand 関数を利用すると乱数を生成できる。

rand(start, end) で start <= 乱数 <= end な実数をランダムに生成する。
擬似乱数の生成には drand48 を利用している。

対応するソースコードは lib/libvmod_std/vmod_stc.c
実体は短いのでコピペ。

double
vmod_random(struct sess *sp, double lo, double hi)
{
        double a;

        (void)sp;

        a = drand48();
        a *= hi - lo;
        a += lo;
        return (a);
}

乱数を使った TTL の設定

/etc/varnish/default.vclvcl_fetch で設定する。

import std;
...
sub vcl_fetch {
     if (req.url ~ "png") {
         set beresp.ttl = 1s * std.random(1, 60);
     }
     return (deliver);
}

vcl ファイルの先頭で std モジュールをインポート
vcl_fetch 関数の中で URL が png にマッチする場合、1秒から60秒までの間で一様な TTL を設定する。

動作確認

画像を9ファイル用意し、HTMLファイル(random.html)でこれら画像を表示する。
このファイルを1秒ごとにリロードする。

Varnish 起動後、1回目のサクセスでは、全リソースがオリジンサーバにリクエストされることを確認。
2回目以降のアクセスでは、TTL が切れたリソースのみオリジンサーバにリクエストされることを確認。

表示するHTMLファイル

9個の画像を表示させているだけ。

<html>
<meta http-equiv="refresh" content="1; URL=./random.html">
<body>
<img src="/images/1.png">
<img src="/images/2.png">
<img src="/images/3.png">
<img src="/images/4.png">
<img src="/images/5.png">
<img src="/images/6.png">
<img src="/images/7.png">
<img src="/images/8.png">
<img src="/images/9.png">
</body>
</html>

リロード方法

meta タグの refresh を使って1秒ごとにリロードする。

オリジンサーバへのリクエストを確認

TTL をダンダムにした効果がでているか、実際にオリジンサーバー nginx のアクセスログを確認

TTLがランダムな場合のオリジンサーバへのアクセス

127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /random.html HTTP/1.1" 200 383 "-"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/1.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/2.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/4.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/7.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/3.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/6.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/5.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/8.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...
127.0.0.1 - - [25/Oct/2013:15:48:25 +0000]  "GET /images/9.png HTTP/1.1" 200 707 "http://localhost/random.html"  ...

1回目のアクセス 15:01:04 では全リソースに対してオリジンサーバーにリクエストしている。
2回目以降のアクセスでは TTL が切れたリソースのみオリジンサーバにアクセスする。
TTL がランダムなため、期待通りオリジンサーバへのリクエスト時刻がばらけている。

127.0.0.1 - - [25/Oct/2013:15:48:40 +0000]  "GET /images/5.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:48:42 +0000]  "GET /images/1.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:48:48 +0000]  "GET /images/8.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:48:51 +0000]  "GET /images/4.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:48:52 +0000]  "GET /images/7.png HTTP/1.1" 200 707 "http://localhost/random.html" ...

TTLが10秒固定の場合のオリジンサーバへのアクセス

比較のために default.vclset beresp.ttl = 10s; と TTL を 10 秒固定にすると、、、

キャッシュなしの状態では全リソースに対してオリジンサーバにリクエスト。

127.0.0.1 - - [25/Oct/2013:15:54:10 +0000]  "GET /random.html HTTP/1.1" 200 383 "-" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/1.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/2.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/4.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/5.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/6.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/7.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/3.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/9.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:11 +0000]  "GET /images/8.png HTTP/1.1" 200 707 "http://localhost/random.html" ...

10秒の TTL が切れたタイミングで一斉にオリジンサーバにリクエストが来る。

127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/1.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/2.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/3.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/4.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/7.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/5.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/6.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/9.png HTTP/1.1" 200 707 "http://localhost/random.html" ...
127.0.0.1 - - [25/Oct/2013:15:54:21 +0000]  "GET /images/8.png HTTP/1.1" 200 707 "http://localhost/random.html" ...

検証用 VCL

ランダム TTL 時には /etc/varnish/default.vcl を次のようにした

import std;

backend default {
 .host = "127.0.0.1";
 .port = "8080";
}

sub vcl_recv {
 set req.backend = default;
}

sub vcl_fetch {
 if (req.url ~ "png") {
 set beresp.ttl = 1s * std.random(1, 60);
 }
 return (deliver);
}

sub vcl_pass {
 return (pass);
}

sub vcl_deliver {
 return (deliver);
}

使い方を誤ると、同じページの画像やCSSのリビジョンがバラバラになって、デザイン崩れの元にもなる。ランダムな ttl を設定しただけで満足しないこと。

Advertisements
Tagged with: , , ,
Posted in middleware, web

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
  • RT @__apf__: How to write a research paper: a guide for software engineers & practitioners. docs.google.com/presentation/d… /cc @inwyrd 4 months ago
  • RT @HayatoChiba: 昔、自然と対話しながら数学に打ち込んだら何かを悟れるのではと思いたち、専門書1つだけ持ってパワースポットで名高い奈良の山奥に1週間籠ったことがある。しかし泊まった民宿にドカベンが全巻揃っていたため、水島新司と対話しただけで1週間過ぎた。 それ… 5 months ago
  • RT @googlecloud: Ever wonder what underwater fiber optic internet cables look like? Look no further than this deep dive w/ @NatAndLo: https… 5 months ago
  • @ijin UTC+01:00 な時間帯で生活しています、、、 10 months ago
  • RT @mattcutts: Google's world-class Site Reliability Engineering team wrote a new book: amazon.com/Site-Reliabili… It's about managing produc… 1 year ago
%d bloggers like this: