使える!サーバ運用の実践テクニック

第14回[キャリアアップ編⑤]varnishを使おう④─実践varnish

大規模コンテンツ配信の仕組みとしてvarnishをテーマに連載してまいりましたが、今回は、実際にサービスでも利用しているxcir氏(いわなちゃん)にご協力いただき、本連載におけるvarnishシリーズをまとめたいと思います。それではxcirさんよろしくお願いします。

はじめまして、xcir(いわなちゃん)といいます。今回は、varnish実践編ということで、運用に役立つテクニックなどをテーマにご紹介できればと思います。なお、今回の内容につきましては特記がない限りCentOS上で動かしたvarnish2.1.4での記載となります。

VCLについて

varnishは複雑な設定をしなくても高速に動きますが、決め細やかな制御を行う際は、VCL(varnish configuration Language)の設定が必要です。VCLは一般的な設定ファイルとは違い、まるで言語のように記述して動作します。

実際にVCLはCに解釈されたあと、コンパイルされ共有ライブラリ(.so)としてvarnishからロードされます。そのため、たとえばApacheの設定のようにon/offの大量に組み合わせてということがありません。その点がvarnishの難しさでもあり、また慣れると楽な点であります。

サブルーチンについて

前回第13回⁠、サブルーチンの種類については説明しましたが、実際どのように連携して動作するかを図1に記載します。赤い矢印の箇所はバックエンドからデータを取得している部分となります。

図1 サブルーチンの連携
図1 サブルーチンの連携

この図は簡易版ではありますが、大体の動作のイメージはつかめるかと思います。なおvarnishを動作させる際によく使うのがvcl_recvとvcl_deliverです。本番運用を前提においても特殊な動作をさせない場合は、この部分の変更で実サービスを提供することができると思います。

VCLのデバッグの仕方(起動するまで)

VCLで複雑な設定をする際はもちろん、簡単な設定を行う際もデバッグが必要です。しかし、varnishの起動スクリプトにはconfigtestのオプションがありません。 毎回varnishをrestartして設定確認というのは実サービス提供を考えると現実的でない部分もあります。そこで以下のコマンドを使用します。

varnishd -d -f [VCLファイル名] -C

このコマンドを使用すると成功した場合はVCLをC言語に解釈した際のコードを、記述ミスがあるとその内容を教えてくれます。

たとえば以下のようなvclを記述したとします。

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

上記VCLはhostの指定行から「;」を抜いていますが、このような記述ミスを、restartをして起動の成否で探し出すのは非常に大変です。

しかし先ほどのコマンドを通してみると

 [root@LIP-APP-01 # varnishd -d -f test.vcl -C
Message from VCC-compiler:
Expected ';' got '.'
(program line 483), at
(input Line 3 Pos 3)
.port = "81";
--#------------

In backend specification starting at:
(input Line 1 Pos 1)
backend default {
#######----------
Running VCC-compiler failed, exit 1
[root@LIP-APP-01#

上記の通り3行目の3文字目が間違っていると指摘してくれます。

VCLのデバッグの仕方(起動してから)

実際に起動してから、どのように動作しているかを確認する際はどうすればいいでしょうか? CやPerlやPHPといった言語でよくやる方法として、printfなどで変数などを出力して確かめてみたことがあると思います。varnishでもバージョン2.1.3から追加されたlogメソッドとvarnishlogコマンドを使うことによって実現が可能です。

まずVCLの任意のサブルーチン内で以下の形で記述をします。

  • log テキスト

そしてログ監視は、以下のコマンドで起動します。

varnishlog -i VCL_Log
細かい利用方法に関しては長くなるので、本連載では割愛します。詳細に関しては、(xcir)が記載しているwikiのvarnishのログ(Logging in varnish)を参照していただければ幸いです。

それでは実践編です。たとえばvcl_recvにおいて、リクエストのURLが/test/と一致する際にログを出したい際は、以下の通り記載します。

sub vcl_recv {
    if(req.url~"^/test/"){
    log "[req.url@test]"req.url;
    }
}

これをvarnishlogコマンドを起動してwgetで以下のリクエストをしてみると、以下のようなログが出力されます。

wgetでリクエスト
wget http://localhost/test/a.jpg
ログの内容
[root@LIP-APP-01 # varnishlog -i VCL_Log
12 VCL_Log c [req.url@test]/test/a.jpg

また、以下のようにwgetした際は当然ながらif内に入らないのでログは出力されません。このような形でログに出力させながらデバッグをしてけば良いかと思います。

wgetでリクエスト
wget http://localhost/hoge/a.jpg
LOGの内容

(LOGには出力されません)

ちょっと高度なVCLの使い方~インラインC~

もしデフォルトのVCLの記述で表現しきれないことがあったらどうすればいいでしょうか? 答えは「VCL中にC言語でコードを書く」です。以下のようにVCL中にCのコードを書くことができます。

C{
    int hoge;
    hoge=0;
    hoge++;
}C
Cのコードは任意の箇所に書くことができます。

実際のところどのように使えばいいでしょうか? たとえばpurgeのリクエストが発行されたらそのリモートIPなどの情報をsyslogに飛ばすということもできます。varnishが用意しているCの関数などは、以下のように先ほどのデバッグをする際のコマンドを利用して出力されたCのコードを参照しながらが基本となります。

varnishd -d -f [VCLファイル名] -C

もともとVCLに関しても未知なるエラーのデバックは困難ですが、このようなCで書かれたコードは更に困難を極める事があります。以下によく陥るポイントを解説します。

Cで書いた結果をVCL変数のresp.*などに入れたい

VRT_SetHdrを利用します。書き方の例は以下のようになります。

sub vcl_deliver {
    C{
        VRT_SetHdr(sp, HDR_RESP, "\011TestTest:", "hello", vrt_magic_string_end);
    }C
}

この記述では、resp.http.TestTestに対してhelloを入れています。

以下に、引数について解説します。

第一引数
固定でspを渡します。
第二引数
何処のヘッダに対して操作を行うか指定します。内容は、以下のものがあります。
  • HDR_REQ
    req.http.*に相当

  • HDR_RESP
    resp.http.*に相当

  • HDR_OBJ
    obj.http.*に相当

  • HDR_BEREQ
    bereq.http.*に相当

  • HDR_BERESP
    beresp.http.*に相当

第三引数
resp.http.TestTestのTestTest部分を特定します。フォーマットは以下の通りです。
  • \0+文字列長の8進数2桁(1桁の場合は0パディング)+文字列

第四引数以降
任意の文字列(char*)で複数個指定が可能です。複数した場合は連結されます。
最後の引数
vrt_magic_string_endを固定で指定します。

なお、VCLの関数は大体文字列を扱うようになっており、その場合に最後はvrt_magic_string_endで終わりますので注意してください。忘れると起動はするものの動かなかったりします。

VCLの小技

別ファイルの埋め込み

たとえばbackendの設定やaclの設定だけを切り出して、別ファイルで管理したいことがあると思います。その際はincludeを利用し、以下のように切り出したVCLを読み込みたい任意の場所で指定することで実現します。

include "ファイルパス";

文字列の連結

たとえば、PHPで文字列の連結をする際は

$str1."test2";

C#では

str1+"test2";

といった感じで書きますが、varnishでは以下のように記述します。

str1"test2"

文字列は特に演算子を使わずに連結することができます。

他にも大技小技、さまざまなテクニックを(xcir)のブログで紹介していますので、参考にしていただければと思います。

実運用での注意点

さて、今回はVCLの記述法だけではなく私(xcir)が実際にある程度のトラフィックで運用した際に陥った点をお伝えします。

さて最後の事例として、みなさんにも考えていただきたいです。

いかがでしたでしょうか? さすが実践サービスで利用しているだけあり、今までの連載の総仕上げに相応しい内容になったかと思います。また、私も、xcir氏も、このvarnishの手軽さからは想像できないほど得られる効果に、もっともっと普及し、高度な(新しい)利用用途等が発見されればと思っております。

おすすめ記事

記事・ニュース一覧