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

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

この記事を読むのに必要な時間:およそ 3 分

ちょっと高度な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)が実際にある程度のトラフィックで運用した際に陥った点をお伝えします。

【事例1】
VCLの動的ロードを行ってそのまま運用した際に,子プロセスのpanicなどで再起動がかかると極稀に設定がロードできずに起動してこない。

原因:なんらかの原因で子プロセスが死亡した際,varnishはデフォルトで自動的に再起動しますが,VCLを動的ロードで変えてる場合,極稀にVCLのコンパイルした共有ライブラリを見失い子プロセスの再起動に失敗することがあります。

対策:これを防ぐにはある程度設定が固まった時点でvarnishをrestartしてしまえば防げます。そもそも勝手に再起動が起こる状況もおかしいのでなぜ起きたかは調べたほうが良いかと思います。varnish公式のTracを見ると該当のチケットがあるかもしれませんので,調べて必要ならパッチを当てるといいでしょう。

【事例2】
多段でvarnishを構築した際に,特定の携帯でのリロードの際に画像が見えない。

補足:これは現在の2.1.4では起きていませんが,2.0.6で運用した際に起きた問題です。この時の状況は以下の通りでした。

  1. auの一部端末でリロードすると画像が×になる
  2. ステータスは400になる
  3. 多段でvarnishを経由していると起きる

原因:リクエストヘッダのサイズが多すぎて,中間のvarnishで付与していたヘッダ+端末でリロードした際に追加されるヘッダでサイズオーバーを起こしてしまい400を返してしまいました。

対策:この時の私のミスとして,構成を大幅に変えたにも関わらず十分な時間監視していなかったということがあります。当然,全ての携帯端末で確認ができる訳ではないのでリリース前に発見する事が難しい事もあります。思わぬ落とし穴があったりするので構成を変更する際は注意深く監視するといいでしょう。

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

【事例3】
過去の画像は返却できるが最新の画像が返却できない。

補足:この時の状況は以下のような場合でした。

  1. すでにキャッシュしている画像については普通に返却する
  2. たまに恐ろしく重い画像がある
  3. 事象が起きたURLに対しては再現性は低い
  4. 突然解決したりする
  5. varnishがエラーを吐いているが再起動はしていない

原因:結論から言いますと,これはvarnishの障害ではなく,スイッチ障害でした。インターネットにつながる線は正常だったので,既にキャッシュしている画像は返却できていましたが,バックエンドに向かう線がつながっているスイッチが障害を起こし,エラーパケットが出ていました。そのため極端に重かったり,最悪タイムアウトしたりしていました。しかし,一度表示できればキャッシュしてしまうので再現がなかなか取れなかったりします。

実運用をする場合は単純にミドルウェアでの設定ミスやバグだけではなく,このようなスイッチ障害を起こして結果として障害が起きているということもあります。障害に対しては常に広い視点を持って対処したいということを述べて終としたいと思います。

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

著者プロフィール

高岡将(たかおかすすむ)

大手金融,独立系SIerにて気がつけば計18年以上のキャリアを重ねる。バランス感覚に長け,インフラ/アプリ,プレイヤ/マネージャなど関係なくこなし,「いそうだけどいないタイプ」と評価される。

仕事以外では,自転車,ジョギング,サックス等を趣味にし,密かに「エンジニアと健康」についてダイエット成功論の連載を企む。


xcir(いわなちゃん)

携帯コンテンツ業界でインフラ関連に従事。ここ最近は,積極的にvarnishを利用して分散,高速化等のテーマで活動中。

URL:http://blog.xcir.net

Twitter:@xcir