monolithic kernel

HTTPでVarnishのキャッシュをpurge

Varnishは標準でvarnishadmコマンドとtelnetによる管理が実装されていますが、VCLを少し記述するとHTTPで操作することもできます。認証がかけられないという問題はありますが、IPアドレスによる制限は可能ですし、Webアプリに組み込むのであればHTTPのほうが楽な気がします。

今回はWebアプリで使う頻度が高いであろうpurgeをHTTPから実行してみます。

VCLの記述

methodがPURGEのリクエストが送られてきた場合にはreq.urlをパスの正規表現と解釈してpurgeを行うように記述します。また、以下の例ではHostヘッダで対象とするVirtualHostを指定できるようにしています。

backend app {
    .host = "127.0.0.1";
    .port = "9000";
    .connect_timeout = 30s;
}

// Access Control List
// 接続を許可するホストの一覧を記述している
acl purge {
    "localhost";
}

sub vcl_recv {
    if (req.request == "PURGE") {
        // ~ 演算子を使うとACLに含まれるかどうかを判定できる
        if (!client.ip ~ purge) {
            error 405 "Not allowed.";
        }
        // パターンにマッチするキャッシュを削除する
        purge("req.http.host == " req.http.host " && req.url ~ " req.url);
        error 200 "Purged.";
    }
    elsif (req.http.host == "app.example.com") {
        // purge以外の処理
        set req.backend = app;
    }
    return(lookup);
}

コマンドラインからの呼び出し

curl -X PURGE -H 'Host: app.example.com' 'http://localhost:6081/posts/' -I
HTTP/1.1 200 Purged
Server: Varnish
Retry-After: 0
Content-Type: text/html; charset=utf-8
Content-Length: 451
Date: Sun, 16 Jan 2011 06:35:25 GMT
X-Varnish: 528212595
Age: 0
Via: 1.1 varnish
Connection: close

Rubyからの呼び出し(Net::HTTP)

require 'net/http'

class Net::HTTP
  class Purge < Net::HTTPRequest
    METHOD = 'PURGE'
    REQUEST_HAS_BODY = false
    RESPONSE_HAS_BODY = true
  end
end

Net::HTTP.start('localhost', 6081) do |http|
  req = Net::HTTP::Purge.new('/posts/')
  req['Host'] = 'app.example.com'
  p http.request(req)
end

Rubyからの呼び出し(EventMachine)

EventMachineのほかにEM-HTTP-Requestを使っています。

require 'eventmachine'
require 'em-http'

class EventMachine::HttpRequest
  def purge(options = {}, &block)
    setup_request(:purge, options, &block)
  end
end

EventMachine.run do
  http = EventMachine::HttpRequest.new('http://localhost:6081/posts/').purge(:head => { 'Host' => 'app.example.com' })

  http.callback do
    p http.response
    EventMachine.stop_event_loop
  end

  http.errback do
    p http.response
    EventMachine.stop_event_loop
  end
end

参考