大規模コンテンツ配信の仕組みとして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に記載します。赤い矢印の箇所はバックエンドからデータを取得している部分となります。
この図は簡易版ではありますが、大体の動作のイメージはつかめるかと思います。なおvarnishを動作させる際によく使うのがvcl_recvとvcl_deliverです。本番運用を前提においても特殊な動作をさせない場合は、この部分の変更で実サービスを提供することができると思います。
VCLのデバッグの仕方(起動するまで)
VCLで複雑な設定をする際はもちろん、簡単な設定を行う際もデバッグが必要です。しかし、varnishの起動スクリプトにはconfigtestのオプションがありません。 毎回varnishをrestartして設定確認というのは実サービス提供を考えると現実的でない部分もあります。そこで以下のコマンドを使用します。
このコマンドを使用すると成功した場合はVCLをC言語に解釈した際のコードを、記述ミスがあるとその内容を教えてくれます。
たとえば以下のようなvclを記述したとします。
上記VCLはhostの指定行から「;」を抜いていますが、このような記述ミスを、restartをして起動の成否で探し出すのは非常に大変です。
しかし先ほどのコマンドを通してみると
上記の通り3行目の3文字目が間違っていると指摘してくれます。
VCLのデバッグの仕方(起動してから)
実際に起動してから、どのように動作しているかを確認する際はどうすればいいでしょうか? CやPerlやPHPといった言語でよくやる方法として、printfなどで変数などを出力して確かめてみたことがあると思います。varnishでもバージョン2.1.3から追加されたlogメソッドとvarnishlogコマンドを使うことによって実現が可能です。
まずVCLの任意のサブルーチン内で以下の形で記述をします。
そしてログ監視は、以下のコマンドで起動します。
それでは実践編です。たとえばvcl_recvにおいて、リクエストのURLが/test/と一致する際にログを出したい際は、以下の通り記載します。
これをvarnishlogコマンドを起動してwgetで以下のリクエストをしてみると、以下のようなログが出力されます。
また、以下のようにwgetした際は当然ながらif内に入らないのでログは出力されません。このような形でログに出力させながらデバッグをしてけば良いかと思います。
ちょっと高度なVCLの使い方~インラインC~
もしデフォルトのVCLの記述で表現しきれないことがあったらどうすればいいでしょうか? 答えは「VCL中にC言語でコードを書く」です。以下のようにVCL中にCのコードを書くことができます。
実際のところどのように使えばいいでしょうか? たとえばpurgeのリクエストが発行されたらそのリモートIPなどの情報をsyslogに飛ばすということもできます。varnishが用意しているCの関数などは、以下のように先ほどのデバッグをする際のコマンドを利用して出力されたCのコードを参照しながらが基本となります。
もともとVCLに関しても未知なるエラーのデバックは困難ですが、このようなCで書かれたコードは更に困難を極める事があります。以下によく陥るポイントを解説します。
Cで書いた結果をVCL変数のresp.*などに入れたい
VRT_SetHdrを利用します。書き方の例は以下のようになります。
この記述では、resp.http.TestTestに対してhelloを入れています。
以下に、引数について解説します。
- 第一引数
- 固定でspを渡します。
- 第二引数
- 何処のヘッダに対して操作を行うか指定します。内容は、以下のものがあります。
- 第三引数
- resp.http.TestTestのTestTest部分を特定します。フォーマットは以下の通りです。
- 第四引数以降
- 任意の文字列(char*)で複数個指定が可能です。複数した場合は連結されます。
- 最後の引数
- vrt_magic_string_endを固定で指定します。
なお、VCLの関数は大体文字列を扱うようになっており、その場合に最後はvrt_magic_string_endで終わりますので注意してください。忘れると起動はするものの動かなかったりします。
VCLの小技
別ファイルの埋め込み
たとえばbackendの設定やaclの設定だけを切り出して、別ファイルで管理したいことがあると思います。その際はincludeを利用し、以下のように切り出したVCLを読み込みたい任意の場所で指定することで実現します。
文字列の連結
たとえば、PHPで文字列の連結をする際は
C#では
といった感じで書きますが、varnishでは以下のように記述します。
文字列は特に演算子を使わずに連結することができます。
他にも大技小技、さまざまなテクニックを私(xcir)のブログで紹介していますので、参考にしていただければと思います。
実運用での注意点
さて、今回はVCLの記述法だけではなく私(xcir)が実際にある程度のトラフィックで運用した際に陥った点をお伝えします。
さて最後の事例として、みなさんにも考えていただきたいです。
いかがでしたでしょうか? さすが実践サービスで利用しているだけあり、今までの連載の総仕上げに相応しい内容になったかと思います。また、私も、xcir氏も、このvarnishの手軽さからは想像できないほど得られる効果に、もっともっと普及し、高度な(新しい)利用用途等が発見されればと思っております。