使用 Varnish 加速你的 Web 网站
2015-08-05 16:45
615 查看
转自:http://www.oschina.net/translate/speed-your-web-site-varnish Varnish可以有效降低web服务器的负载,提升访问速度。根据官方的说法,Varnish是一个cache型的HTTP反向代理。 按照HTTP协议的处理过程,web服务器接受请求并且返回处理结果,理想情况下服务器要在不做额外处理的情况下,立即返回结果,但实际情况并非如此。本文将分析在web服务器处理请求的过程中,Varnish能起到什么作用。 |
web服务器的实现千差万别,但典型的处理过程是相同的,都要经过一系列的步骤来处理接收到的每个请求。有可能需要启动一个进程来处理请求,有可能需要从磁盘上载入文件,或者启动内部线程来编译执行一些脚本。在执行脚本的过程中,还会有进行很多别的动作,比如进行数据库查询,读取文件等等。当成百上千个请求并发访问时,服务器的负载会很快上升,出现系统资源不够的情况。一种更糟的情况是,很多请求是重复的,但web服务器无法记住曾经作出的响应,还会重复上面复杂的处理过程。 |
当把Varnish部署上之后,web请求的处理过程会有一些变化。客户端的请求将首先被Varnish接受。Varnish将分析接收的请求,并将其转发到后端的web服务器上。后端的web服务器对请求进行常规的处理,并将依次将处理结果返回给Varnish。 但Varnish的功能并非仅限于此。Varnish的核心功能是能能将后端web服务器返回的结果缓存起来,如果发现后续有相同的请求,Varnish将不会将这个请求转发到web服务器,而是返回缓存中的结果。这将有效的降低web服务器的负载,提升响应速度,并且每秒可以响应更多的请求。Varnish速度很快的另一个主要原因是其缓存全部都是放在内存里的,这比放在磁盘上要快的多。诸如此类的优化措施使得Varnish的相应速度超乎想象。但考虑到实际的系统中内存一般是有限的,所以需要手工配置一下缓存的空间限额,同时避免缓存重复的内容。 |
下面来看一下Varnish的安装过程。可以从源码进行安装,也可以直接使用一些发行版中的预编译包。当期Varnish的版本是3.0.3(译者注:目前最新是2013年6月17日发布的3.0.4版),本文将基于3.0.3进行源码安装。需要注意的是,2.X版的Varnish和3.X的配置文件格式发生了变化。可以从Varnish的官方网站上找到2.x到3.x升级的细节。 从源码进行安装经常遇到的问题是系统缺少某些依赖的文件。可以从Varnish的安装文档里找到编译所需的所有依赖的文件。 以root身份运行如下命令来下载和安装Varnish。 ? |
在运行varnishd之前,需要先配置后端的web服务器,参照如下格式编辑default.vcl文件,更改为你自己web服务器配置。 ? ? |
-f : 指定配置文件位置 |
启动完毕之后,Varnish就可以处理并转发请求了。在转发过程中,varnish会尽可能的缓存结果。我们通过下面几个简单的GET请求,来看看varnish是如何工作的。首先,运行如下命令: ? ? |
在这里GET命令的选项无所谓。需要注意的是varnish返回的响应,varnish会增加三个相应头信息,分别是“X-Varnish”、“Via”和“Age”。这些头信息在Varnish的处理过程中非常有用。X-Varnish头信息的后面会有一个或两个数字,如果是一个数字,就表明varnish在缓存中没有发现这个请求,这个数字的含义是varnish为这个请求所做的标记ID。如果X-Varnish后是两个数字,就表明varnish在缓存中命中了这个请求,第一个数字是请求的标识ID,第二个数字是缓存的标识ID。“Via”头信息表明这个请求将经过一个代理。“Age”头信息标识出这个请求将被缓存多长时间(单位:秒)。首次请求的“Age”为0,后续的重复请求将会使Age值增大。如果后续的请求没有是“Age”增加,那就说明varnish没有缓存这个响应的结果。 |
现在来看看 varnishstat 命令启动执行的情况,如下图所示: 图2. varnishstat 命令 最重要的是 cache_hit 和 cache_miss 这两行。如果没有任何命中,cache_hits 不会显示。当越来越多的请求进来,计数器会不断更新以反应新的命中数和未命中数。 接下来看看 varnishlog 命令: 图3. varnishlog 命令 |
上图显示varnish接受请求并作出响应的内部细节,下面是varnish官方文档中的解释: 第一列是一个乱数,用来标识当前请求。第一列数字相同的行属于一HTTP请求序列。第二列是日志信息的标签,所有的日志信息会分类标记,以“Rx”开头的为接收的数据,以“Tx”开头的为发送的数据。第三列表示数据在客户端,vainish和web服务器之间的传输状态。第四列是被日志记录的数据。 varnishlog命令有很多的选项可以在查询时使用。强烈推荐在排错或测试时使用varnishlog。可以阅读varnish的man page来查看这个命令的详细使用情况。下面是一些使用的例子。 |
显示varnish和客户端之间的通信(忽略后端web服务器): ? ? ? ? |
现在通过上述命令,我们可以控制varnish的启动和关闭,可以检查缓存的命中情况,下一个问题是varnish到底缓存了什么,会存多久? varnish的默认缓存策略是偏向保守的(可以通过配置改变)。它默认只缓存get请求和HEAD请求。不会缓存带有Cookie和认证信息的请求,也不会缓存带有Set-Cookie或者有变化的头信息的响应。varnish也会检查请求和响应中的Cache-Control头信息,这个头信息中会包含一些选项来控制缓存行为。当Cache-control中Max-age的控制和默认策略冲突时,varnish不会单纯的根据Cache-control信息就改变自己的缓存行为。例如:Cache-Control: max-age=n,n为数字,如果varnish收到web服务器的响应中包含max-age,varnish会以此值设定缓存的过期时间(单位:秒),否则varnish将会设置为参数配置的时间,默认为120秒。 |
varnish的默认配置可以适应多数情况。例如,默认的default_ttl缓存过期时间是120秒。配置文件的详细解释可以阅读varnishd的man page。如果你想改变某些默认设置,一种方式是通过命令行varnishd加上-p参数,这将重启varnishd,并清空缓存。另外一种方式是使用varnish的管理接口,要使用varnish的管理接口需要以-T参数启动varnish,这个参数指定了,varnish管理接口的监听端口。然后使用varnishadm命令连接到varnish的管理接口上,然后实时的查询varnish的运行参数,或者更改新的参数,这些都不需要重启varnish。 |
在修改default.vcl配置之前,我们先来看一下varnish处理http请求的一个完整过程。我们将之成为一个请求/响应周期(request/response cycle)。这个过程始于varnish收到客户端的请求,varnish将检查这个请求,并将其标记存储,接下来varnish将根据一定的策略决定是将这个请求直接转发,还是检查缓存。如果是第一种情况,varnish会将请求直接转发到后端的服务器上,并且将服务器的响应返回给你客户端。如果是第二种情况,varnish会进行一个缓存查询的过程,如果缓存命中,varnish会将缓存中结果返回给客户端,如果缓存中没有,varnish会将此请求转发给后端的服务器,并将服务器的响应先进行缓存,然后再转发给客户端。 |
了解完varnish对请求和响应处理的过程之后,我们来讨论一下如何改变varnish的缓存策略。varnish有一系列的子功能来完成上述处理过程,每一个子功能完成处理过程的一个部分。每一个子功能的执行结果传递给下一个子功能。所以我们可以通过改变子功能的返回值来改变varnish的处理动作。每一个子功能都在default.vcl中有一个默认定义,可以通过改变这些值来定制varnish的功能。 |
varnish的子程序在default.vcl中有默认的配置,如果你重新配置了某一个功能,并不意味着默认的动作一定不会执行。一般情况下,如果你重新配置了某一个功能,但是没有返回值,varnish将会执行默认的动,因为所有的varnish子程序都会有一个返回值。这可以看作varnish的一种容错机制。 |
下一个子程序是vcl_pass。如果在vcl_recv中返回了“pass”,将执行vcl_pass。vcl_pass有两种返回值,pass:继续转发请求到后端web服务器。restart:将请求重新返回给vcl_recv。 vcl_miss和vcl_hit将会根据varnish的缓存命中情况来执行。vcl_miss的执行有两种情况,一是从后端服务器获取响应结果,并且在本地缓存(fetch),二是从后端获取到响应,但本地不缓存(pass)。如果varnish缓存命中,将会执行vcl_hit,会有两个选择,一个直接将缓存的结果返回给客户端(deliver),二是丢弃缓存,重新从后端服务器获取数据(pass)。 当从后端服务器获取到数据之后,将会执行vcl_fetch过程,在这里可以通过beresp对象来访问响应数据,返回两种处理结果;deliver:按计划将数据发送给客户端,restart,退回这个请求。 |
在vcl_deliver子程序中,可以将响应结果发送给客户端(deliver),结束这个请求,同时根据不同情况决定是否缓存结果。也可以返回“restart”值,来重新开始这个请求。 如前所述,通过default.vcl来控制varnish的缓存策略,通过子程序的返回值来控制varnish的动作。子程序的返回值可以基于req和resp对象,也可以基于客户端对象,服务端对象或者后端服务器对象。但在子程序处理过程中,上述数据对象并非一直都可用。另外要注意子程序的返回值会有一定的限制范围,一个难点就是记住在什么时候,哪个子程序中什么数据对象是可用的,合法的返回值有哪些。为了让这个问题更清晰一些,下面是一张表格,可以在修改配置的时候快速参考: |
|
client | server | req | bereq | beresp | resp | obj | |
vcl_recv | X | X | X | ||||
vcl_pass | X | X | X | X | |||
vcl_miss | X | X | X | X | |||
vcl_hit | X | X | X | X | |||
vcl_fetch | X | X | X | X | X | ||
vcl_deliver | X | X | X | X |
表2. 各子程序的合法返回值.
pass | lookup | error | restart | deliver | fetch | pipe | hit_for_pass | |
vcl_recv | X | X | X | X | ||||
vcl_pass | X | X | X | |||||
vcl_lookup | ||||||||
vcl_miss | X | X | X | |||||
vcl_hit | X | X | X | X | ||||
vcl_fetch | X | X | X | X | ||||
vcl_deliver | X | X | X |
注意:
请仔细阅读vcl的文档来了解相关子程序,返回值以及可用的数据对象。下面是一些实际的例子:
修改HTTP请求的 Host 头信息:
?
下面是默认 vcl_recv 子程序的一个片段:
?
这是默认的vcl_recv配置文件的片段,在这个配置中如果发现请求不是GET或者HEAD,varnish将会直接pass这个请求,并且不会缓存这个请求的响应,如果是GET或HEAD,将会到缓存中进行查找。 匹配特定的URL,移除请求中的Cookie信息: ? |
在对图片文件的响应头中中移除set-Cookie: ? 现在我们想朝响应信息中增加一个"X-Hit"的头信息,当缓存命中的时候,这个值为1,未命中的时候为0。根据上文,判断缓存命中的最简单的办法是在vcl_hit中。当缓存命中是会调用vcl_hit,因此可以考虑在vcl_hit中设置这个头信息,但从上文表1中我们看到,vcl_hit里beresp和resp都是不可用的。一个可行的办法就是在请求中设置里一个临时头信息,然后在后续的处理过程中真正进行设置。下面我们看一下这个问题是如何解决的: |
在响应头信息中增加“x-hit”: ? 下面我们看一个针对此问题错误的解决办法: |
增加“x-hit”头信息(错误的方法): ? 避免这些问题的办法是熟练掌握上述的表1的内容,并且在实际工作中多做测试。 |
下面的配置可以让varnish将所有的数据缓存一个小时(不建议在真实环境中使用) ? 一旦varnish运行生效之后,你可以通过一些负载测试工具来测试性能的改善。我通常使用的测试工具是apache自带的ab,可以从apache的安装包里找到,或者通过一些第三方的包管理器进行安装。可以在apache的网站上找到ab的使用文档。 |
在下面的测试例子中,apache2.2监听在80端口,varnish监听在6081端口。用来做测试的页面是一个非常简单的perl CGI脚本,只输出一个单行的HTML文件。通过访问相同的URL来测试apache和varnish的不同表现。为避免网络因素的影响,所有的测试都在本机执行。测试中使用的ab选项非常简单,也可以试着去改变这些选项,看看是什么结果。 首先进行一个1000次的请求(n=1000),并发数量1个(c=1). 先测试apache: ? 图 4. Apache测试结果 |
再测试varnish: ? 图 5. varnish测试结果 ab的测试输出里包含很多信息,最基本的性能指标有“Time per request”和“Requests per second(rps)”。 从上述测试结果来看,apache的每个请求在1ms以上(780rps),而varnish在0.1ms(7336rps)比apache高了10倍。 从这个测试结果说明varnish的速度比apache快,至少在当前环境下是这样。可以尝试改变ab的选项来进行不同的测试,例如改变并发访问数量。 |
系统负载是反映CPU运行状况的指标,通常情况下系统中每个CPU核心的负载应该在1.0以下。如果你的系统中有4个CPU核心,理想的系统负载应该在4.0以下。 |
测试的时候除了关注系统的响应时间之外,还要看系统资源的使用情况。当测试请求持续很长时间时,我们比较一下两者的系统资源使用情况。监控的指标就是系统的负载(system load)和磁盘IO(%iowait)。系统负载可以从top命令里查看,%iowait可以从iostat命令看到。在测试过程中需要同时关注这两个指标,我们打开两个终端分别运行top和iostat。 运行iostat,2秒更新一次: ? ? |
使用ab对Apache进行测试: ? 图 6. Apache 下系统压力测试流量记录 使用ab测试Varnish: ab -c 50 -n 1000000 http://localhost:6081/cgi-bin/test[/code] |
相关文章推荐
- Hadoop基本架构介绍
- 利用img标签,可以为网站设置多张默认图片
- 功能型网站建设如何报价?
- Puppet整合Foreman(一):架构说明
- 大型网站核心架构要素
- Android 谷歌 开源 通信框架 VOLLEY(五)——源码架构设计
- 浅谈USB驱动架构
- 网站优化之网站结构诊断技巧
- 开源项目架构分析之 -- Asterisk
- 大型网站架构演变和知识体系
- 怎么让网站在浏览器网址前面显示小图标?
- 使用百度统计对网站进行流量分析和统计
- launcher架构解析
- 粗略地在iOS中使用URLManager架构
- 可伸缩系统的架构经验
- Tumblr:150亿月浏览量背后的架构挑战
- TravelCMS旅游网站系统前台诞生记-2(后台框架篇)
- TravelCMS旅游网站系统前台诞生记-2(后台框架篇)
- uC/OS-II内核架构解析(1)---嵌入式RTOS(转)
- 网站服务架构