Varnishを利用したWEBサイト高速化について(2)

手軽に導入できて簡単にパフォーマンス向上が見込めるVarnishを利用したWEBサイト高速化についてご紹介致します。

前回の続きですが、今回はVarnishの基本的な処理の流れと具体的な活用例をご紹介します。

以下定義情報を載せておりますが、Varnish3.0系の情報で記載しております。

Varnishの基本的な処理の流れ

前回述べた通り、Webページの表示は、WebブラウザとWebサーバ間の複数HTTPのやり取りで成り立っています。その中でVarnishはリバースプロキシとして、WebブラウザとWebサーバの間に立って要求を代理で処理(応答)する役目を担います。

Varnishの設定はVCL(Varnish Configuration Language)という独自の設定言語を利用して行います。
VarnishはVCLは主に以下の通り構成されています。

backend
Varnishがリクエストを送るバックエンドのサーバ情報を定義する
vcl_recv
リクエストの内容から判断してどういった振り分けをするか初期処理をする
vcl_hash
キャッシュの有無を確認する
vcl_miss
キャッシュがない場合にバックエンドに問い合わせて応答を待つ
vcl_fetch
バックエンドからの応答が返ってきた際に、そのコンテンツをキャッシュしてよいかどうかを判断する|
vcl_deliver
クライアントにコンテンツを返す
図:Varnishの処理の流れとサブルーチン

Varnishの基本設定や導入手順は多くのサイトで掲載があるため、今回はケース毎の設定例を記載します。

複数のバックエンドを定義し、バックエンドリクエストのバランシングが可能です。

以下のように複数のバックエンドを指定することでバックエンドへのリクエストを分散することが可能です。
バランシングの方式はラウンドロビン方式で記載しておりますが、ランダム方式も可能です。
定義は任意ですが、ヘルスチェックも行えるため、常に正常なバックエンドサーバに対してリクエストを行えます。

              
  backend backend1 {
     .host = "XXX.YYY.ZZZ.AAA";
     .port = "80";
     .probe = {
        .interval = 30s;
        .timeout = 5s;
        .window = 5;
        .threshold = 3;
        .request =
            "GET /healthcheck HTTP/1.1"
            "Host: example.com"
            "Connection: close";
     }
  }

  backend backend2 {
     .host = "XXX.YYY.ZZZ.BBB";
     .port = "80";
     .probe = {
        .interval = 30s;
        .timeout = 5s;
        .window = 5;
        .threshold = 3;
        .request =
            "GET /healthcheck HTTP/1.1"
            "Host: example.com"
            "Connection: close";
     }
  }

  director backend round-robin {
     {
        .backend = backend1;
     }
     {
        .backend = backend2;
     }
  }

  sub vcl_recv {
  …
      # Set the backend
      set req.backend = backend;
  …
  }
              
            

特定のUser-Agentの場合にバックエンドのリクエスト先を変えることが可能です。

例えばスマートフォンサイトとPCサイトが別々のサーバで処理していた場合、以下のようにバックエンドサーバを変えることができます。

              
  backend backend-PC {
     .host = "XXX.YYY.ZZZ.AAA";
     .port = "80";
  }

  backend backend-Mobile {
     .host = "XXX.YYY.ZZZ.BBB";
     .port = "80";
  }

  sub vcl_recv {
  …
      # Set the backend
      set req.backend = backend-PC;

      # 特定のUser-Agentを遮断
      if (req.http.User-Agent ~ "(iPhone|iPod|Android.*Mobile)") {
          set req.backend = backend-Mobile;
      }
  …
  }
                
            

特定のIPアドレスやUser-Agentからのリクエストを制限できます。

サイトを運用しているとDDoSのようなサーバ負荷を招くリクエストに遭遇することがあると思います。
Varnishを窓口にすれば、特定のIPやUser-Agentからのリクエストをバックエンドに流さないよう制限することができます。

              
  sub vcl_recv {
  …
      # 特定のIPアドレスを遮断
      if (
              req.http.X-Forwarded-For ~ "aaa\.bbb\.ccc\.ddd" ||
              req.http.X-Forwarded-For ~ aaa\.bbb\.ccc\.eee"
      ) {
         error 404;
      }

      # 特定のUser-Agentを遮断
      if (req.http.User-Agent ~ "crawler example") {
         error 404;
      }

      # 特定のIPアドレスかつUser-Agentを遮断
      if (req.http.User-Agent ~ "crawler example") {
          if (
              req.http.X-Forwarded-For ~ "aaa\.bbb\.ccc\.ddd" ||
              req.http.X-Forwarded-For ~ aaa\.bbb\.ccc\.eee"
             ) {
             error 404;
          }
      }
  …
  }
              
            

以上のように、VCLはIFを柔軟に記載することはできますが、ループは書くことができません。
クライアントから送られてきたリクエスト情報からHTTPヘッダ、デバイス種類、Methodを用いて判定をし、キャッシュをさけたり、キャッシュのタイムアウトを調整したり等の様々の操作を行うことができます。
扱える関数はinportすることで拡張可能なため、利用する際は試してみてください。

VCLの設定反映はサービス再起動のコマンドを実行することで反映できますが、サービス影響を伴うため、以下のように「varnishadm」を利用することでVarnishを再起動する事無く反映が可能です。

VCL反映手順

main.vclがメインで利用しているVCLとした場合、以下の操作で反映が可能です。

              
  # cp -p main.vcl temp.vcl
  # varnishadm vcl.load temp temp.vcl
  # varnishadm vcl.use temp
  # varnishadm vcl.discard boot
  # cp -p main.vcl main.vcl.YYYYMMDD
  # vi main.vcl
  # varnishadm vcl.use boot
  # varnishadm vcl.discard temp