/ 中存储网

提高varnish缓存命中率

2014-04-17 19:34:01 来源:IT技术网
现在varnish已经正常运行了,您可以通过varnish访问到您的web应用程序。如果您的web程序在设计时候没有考虑到加速器的架构,那么您可能有必要修改您的应用程序或者varnish配置文件,来提高varnish的命中率。

既然这样,您就需要一个工具用来观察您和web服务器之间HTTP头信息。服务器端您可以轻松的使用varnish的工具,比如varnishlog和varnishtop,但是客户端的工具需要您自己去准备,下面是我经常使用的工具。

Varnistop

您可以使用varnishtop确定哪些URL经常命中后端。Varnishtop -i txurl 就是一个基本的命令。您可以通过阅读“Statistics”了解其他示例。

Varnishlog

当您需要鉴定哪个URL被频繁的发送到后端服务器,您可以通过varnishlog对请求做一个全面的分析。varnishlog -c -o /foo/bar 这个命令将告诉您所有(-o)包含”/football/bar”字段来自客户端(-c)的请求。

Lwp-request

Lwp-request是www库的一部分,使用perl语言编写。它是一个真正的基本程序,它可以执行HTTP请求,并给您返回结果。我主要使用两个程序,GET和HEAD。

Vg.no是第一个使用varnish的站点,他们使用varnish相当完整,所以我们来看看他们的HTTP 头文件。我们使用GET请求他们的主页:

$ GET -H 'Host: www.vg.no' -Used http://vg.no/

GET http://vg.no/

Host: www.vg.no

User-Agent: lwp-request/5.834 libwww-perl/5.834

200 OK

Cache-Control: must-revalidate

Refresh: 600

Title: VG Nett - Forsiden - VG Nett

X-Age: 463

X-Cache: HIT

X-Rick-Would-Never: Let you down

X-VG-Jobb: http://www.finn.no/finn/job/fulltime/result?keyword=vg+multimedia Merk:HeaderNinja

X-VG-Korken: http://www.youtube.com/watch?v=Fcj8CnD5188

X-VG-WebCache: joanie

X-VG-WebServer: leon

OK,我们来分析它做了什么。GET 通过发送HTTP 0.9的请求,它没有主机头,所以我需要添加一个主机头使用-H选项,-U打印请求的头,-s打印返回状态,-e 答应返回状态的头,-d 丢弃当前的连接。我们正真关心的不是连接,而是头文件。

如您所见VG的头文件中有相当多的信息,比如 X-RICK-WOULD-NEVER是vg.no定制的信息,他们有几分奇怪的幽默感。其他的内容,比如X-VG-WEBCACHE 是用来调试错误的。

核对一个站点是否使用cookies,可以使用下面的命令:

GET -Used http://example.com/ |grep ^Set-Cookie

Live HTTP Headers

这是一个firefox的插件,live HTTP headers 可以查看您发送的和接收的http头。软件在https://addons.mozilla.org/en-US/firefox/addon/3829/下载。或者google“Live HTTP headers”。

The Role of HTTP headers

Varnish认为自己是真正的web服务器,因为它属于您控制。IETF没有真正定义surrogate origin cache 角色的含义,(The role of surrogate origin cache is not really well defined by the IETF so RFC 2616 doesn’t always tell us what we should do.不知如何翻译)

Cache-Control

Cache-control指示缓存如何处理内容,varnish关心max-age参数,并使用这个参数计算每个对象的TTL值。

“cache-control:nocache” 这个参数已经被忽略,不过您可以很容易的使它生效。

在头信息中控制cache-control的max-age,您可以参照下面,varnish软件管理服务器的例子:

$ GET -Used http://www.varnish-software.com/|grep ^Cache-Control

Cache-Control: public, max-age=600

Age

Varnish添加了一个age头信息,用来指示对象已经被保存在varnish中多长时间了。您可以在varnish中找到Age信息:

varnishlog -i TxHeader -I ^Age

Overriding the time-to-live(ttl)

有时候后端服务器会当掉,也许是您的配置问题,很容易修复。不过更简单的方法是修改您的ttl,能在某种程度上修复难处理的后端。

您需要在VCL中使用beresp.ttl定义您需要修改的对象的TTL:

sub vcl_fetch {

if (req.url ~ "^/legacy_broken_cms/") {

set beresp.ttl = 5d;

}

}

Cookies

现在Varnish接收到后端服务器返回的头信息中有Set-Cookie信息的话,将不缓存。所以当客户端发送一个Cookie头的话,varnish将直接忽略缓存,发送到后端服务器。

这样的话有点过度的保守,很多站点使用Google Analytics(GA)来分析他们的流量。GA设置一个cookie跟踪您,这个cookie是客户端上的一个java 脚本,因此他们对服务器不感兴趣。

对于一个web站点来说,忽略一般cookies是有道理的,除非您是访问一些关键部分。这个VCL的vcl_recv片段将忽略cookies,除非您正在访问/admin/:

if ( !( req.url ~ ^/admin/) ) {

unset http.Cookie;

}

很简单,不管您需要做多么复杂的事情,比如您要删除一个cookies,这个事情很困难,varnish也没有相应的工具来处理,但是我们可以使用正则表达式来完成这个工作,如果您熟悉正则表达式,您将明白接下来的工作,如果您不会我建议您找找相关资料学习一下。

我们来看看varnish软件是怎么工作的,我们使用一些GA和一些相似的工具产生cookies。所有的cookies使用jsp语言。Varnish和企业网站不需要这些cookies,而varnish会因为这些cookies而降低命中率,我们将放弃这些多余的cookies,使用VCL。

下面的VCL将会丢弃所有被匹配的cookies。

// Remove has_js and Google Analytics __* cookies.

set req.http.Cookie = regsuball(req.http.Cookie, "(^|;s*)(_[_a-z]+|has_js)=[^;]*", "");

// Remove a ";" prefix, if present.

set req.http.Cookie = regsuball(req.http.Cookie, "^;s*", "");

下面的例子将删除所有名字叫COOKIE1和COOKIE2的cookies:

sub vcl_recv {

if (req.http.Cookie) {

set req.http.Cookie = ";" req.http.Cookie;

set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");

set req.http.Cookie = regsuball(req.http.Cookie, ";(COOKIE1|COOKIE2)=", "; 1=");

set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");

set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");

if (req.http.Cookie == "") {

remove req.http.Cookie;

}

}

这个例子是来自varnish wiki的。

Vary

各式各样的头被发送到web server,他们让HTTP目标多样化。Accept-Encoding头就有这种感觉,当一个服务器分发一个“Vary:Accept-Encoding”给 varnish。Varnish需要cache来自客户端的每个不同的Accept-Encoding。如果客户端只接收gzip编码,varnish不对其他编码服务,那么就可以缩减编码量。

问题就是这样的,Accept-Encoding字段包含很多编码方式,下面是不同浏览器发送的:

Accept-Encodign: gzip,deflate

另一个浏览器发送的:

Accept-Encoding:: deflate, gzip

Varnish可以使两个不同的accept-enconding头标准化,这样就可以尽量减少变体。下面的VCL代码可以是accept-encoding头标准化:

if (req.http.Accept-Encoding) {

if (req.url ~ ".(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {

# No point in compressing these

remove req.http.Accept-Encoding;

} elsif (req.http.Accept-Encoding ~ "gzip") {

set req.http.Accept-Encoding = "gzip";

} elsif (req.http.Accept-Encoding ~ "deflate") {

set req.http.Accept-Encoding = "deflate";

} else {

# unkown algorithm

remove req.http.Accept-Encoding;

}

}

这段代码设置客客户端发送的accept-encoding头只有gzip和default两种编码,gzip优先。

Pitfall – Vary:User-Agent

一些应用或者一些应用服务器发送不同user-agent头信息,这让varnish为每个单独的用户保存一个单独的信息,这样的信息很多。一个版本相同的浏览器在不同的操作系统上也会产生最少10种不同的user-agent头信息。如果您想通过基于user-agent的修改,让他们标准化,您的命中率将收到严重的打击。

Pragma

http 1.0 服务器可能会发送“Pragma:nocache”。 Varnish忽略这个头,您可以轻松的使用VCL来完成这个任务:

In vcl_fetch:

if (beresp.http.Pragma ~ "nocache") {

pass;

}

Authorization

如果varnish收到一个认证请求的头,他将pass这个请求,如果您不打算对这个头做任何操作的话。

Normalizing your namespace

有些站点访问的主机名有很多,比如http://www.varnish-software.com,http://varnish-software.com,http://varnishsoftware.com 所有的地址都对应相同的一个站点。但是varnish不知道,varnish会缓存每个地址的每个页面。您可以减少这种情况,通过修改web配置文件或者通过以下VCL:

if (req.http.host ~ "^(www.)?varnish-?software.com") {

set req.http.host = "varnish-software.com";

}

Purging

增加TTL值是提高命令率的一个好方法,如果用户访问到的内容是旧的,这样就会对您的商务照成影响。

解决方法就是当有新内容提供的时候通知varnish。可以通过两种机制HTTP purging和bans。首先,我们来看一个清理的实例:

HTTP purges

HTTP purges和HTTP GET请求相似,除了这是用来purges的。事实上您可以在任何您喜欢的时间使用这个方法,但是大多数人使用它purging。Squid支持相同的机制,为了让varnish支持purging,您需要在VCL中做如下配置:

acl purge {

"localhost";

"192.168.55.0/24";

}

sub vcl_recv {

# allow PURGE from localhost and 192.168.55...

if (req.request == "PURGE") {

if (!client.ip ~ purge) {

error 405 "Not allowed.";

}

return (lookup);

}

}

sub vcl_hit {

if (req.request == "PURGE") {

# Note that setting ttl to 0 is magical.

# the object is zapped from cache.

set obj.ttl = 0s;

error 200 "Purged.";

}

}

sub vcl_miss {

if (req.request == "PURGE") {

error 404 "Not in cache.";

}

}

您可以看见,使用了新的VCL子程序,vcl_hit和vcl_miss。当您调用lookup时将在缓存中查找目标,结果只会是miss或者hit,然后对应的子程序就会被调用,如果vcl_hit的目标存储在缓存中,并且可用,我们可以修改TTL值。

所以对于vg.no 的无效首页,他们使用varnish做如下处理:

PURGE / HTTP/1.0

Host: vg.no

如果varnish想要丢弃主页,如是很多相同URL的变体在cache中,只有匹配的变体才会被清除。清除一个相同页面的gzip变体可以使用下面命令:

PURGE / HTTP/1.0

Host: vg.no

Accept-Encoding: gzip

Bans

这是另外一种清空无效内容的方法,bans。您可以认为bans是一种过滤方法,您可以禁止某些存在cache中存在的数据。您可以基于我们拥有的元数据来禁止。

Varnish内置的CLI接口就是支持bans的。禁止vg网站上的所有png目标

purge req.http.host == "vg.no" && req.http.url ~ ".png$"

是不是很强大?

在没有被bans命中之前的cache,是能够提供服务的。一个目标只被最新的bans检查。如果您有很多长TTL的目标在缓存中,您需要知道执行很多的Bans对性能照成的影响。

您也可以在varnish中添加bans,这样做需要一点VCL:

sub vcl_recv {

if (req.request == "BAN") {

# Same ACL check as above:

if (!client.ip ~ purge) {

error 405 "Not allowed.";

}

purge("req.http.host == " req.http.host

"&& req.url == " req.url);

# Throw a synthetic page so the

# request wont go to the backend.

error 200 "Ban added"

}

}

这是一个实用varnish的VCL处理ban的方法。添加一个ban在URL上,包含它的主机部分。