高性能HTTP加速器Varnish(管理维护篇)
一、varnishd指令
Varnish启动的命令是/usr/local/varnish/sbin/varnishd,此命令参数较多,用法比较复杂,在命令行执行“/usr/local/varnish/sbin/varnishd –h”即可得到varnishd的详细用法,表2-6列出了varnishd常用参数的使用方法和含义。
表1
- 命令参数 参数含义
- -a address:port 表示varnish对httpd的监听地址及其端口
- -b address:port 表示后端服务器地址及其端口
- -d 表示使用debug调试模式
- -f file 指定varnish服务器的配置文件
- -p param=value 指定服务器参数,用来优化varnish性能
- -P file Varnish进程PID文件存放路径
- -n dir 指定varnish的工作目录
- -s kind[,storageoptions] 指定varnish缓存内容的存放方式,常用的方式有:“-s file,<dir_or_file>,<size>”。
- 其中“<dir_or_file>”指定缓存文件的存放路径,“<size>”指定缓存文件的大小
- -t 指定缺省的TTL值
- -T address:port 设定varnish的telnet管理地址及其端口
- -w int[,int[,int]] 设定varnish的工作线程数,常用的方式有:
- -w min,max
- -w min,max,timeout
- 例如:-w5,51200,30,这里需要说明下,在varnish2.0版本以后,最小启动的线程数不能设定过大,设置过大,会导致varnish运行异常缓慢。
-V 显示varnish版本号和版权信息
二、 配置varnish运行脚本
在安装varnish一节中,已经将varnish的管理脚本拷贝到了相应的目录下,这里稍作修改即可使用,首先修改/etc/sysconfig/varnish文件,根据本章的实例,配置好的文件如下:
- NFILES=131072
- MEMLOCK=82000
- DAEMON_OPTS="-a 192.168.12.246:80 \
- -T 127.0.0.1:3500 \
- -f /usr/local/varnish/etc/vcl.conf \
- -u varnish -g varnish \
- -w 2,51200,10 \
- -n /data/varnish/cache \
- -s file, /data/varnish/cache/varnish_cache.data,4G"
这里需要说明的是,缓存文件“varnish_cache.data”在32位操作系统下,最大仅能支持2G,如果需要更大缓存文件则需要安装64为Linux操作系统。
接着需要修改的文件是/etc/init.d/varnish,找到如下行,改为相应的路径即可:
- exec="/usr/local/varnish/sbin/varnishd"
- prog="varnishd"
- config="/etc/sysconfig/varnish"
- lockfile="/var/lock/subsys/varnish"
其中,“exec”用于指定varnishd的路径,只需修改为varnish安装路径下对应的varnishd文件即可。“config”用于指定varnish守护进程配置文件路径。
两个文件修改完毕,就可以授权、运行/etc/init.d/varnish脚本了,执行如下:
- [root@varnish-server ~]#chmod 755 /etc/init.d/varnish
- [root@varnish-server ~]#/etc/init.d/varnish
- Usage:/etc/init.d/varnish
- {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
从输出可知,此脚本功能强大,可以对varnish进行启动、关闭、查看状态、重启等操作。最后,启动varnish:
- [root@varnish-server ~]# /etc/init.d/varnish start
- Starting varnish HTTP accelerator: [ OK ]
三、管理varnish运行日志
varnish是通过内存共享的方式提供日志的,它提供了两种日志输出形式,分别是:
通过自带的varnishlog指令可以获得varnish详细的系统运行日志。
例如:
- [root@varnish-server ~]#/usr/local/varnish/bin/varnishlog -n /data/varnish/cache
- 0 CLI - Rd ping
- 0 CLI - Wr 200 PONG 1279032175 1.0
- 0 CLI - Rd ping
- 0 CLI - Wr 200 PONG 1279032178 1.0
通过自带的varnishncsa指令得到类似apache的combined输出格式的日志。
例如:
- [root@varnish-server ~]#/usr/local/varnish/bin/varnishncsa -n /data/varnish/cache
也可以将日志输出到一个文件中,通过“-w”参数指定即可:
- [root@varnish-server ~]#/usr/local/varnish/bin/varnishncsa -n /data/varnish/cache \
- >-w /data/varnish/log/varnish.log
varnish两种日志输出形式中,第一种在大多数情况下并不是必须的,这里重点介绍下第二种日志输出形式的配置方式。
下面编写一个名为varnishncsa的shell脚本,并把此文件放到/etc/init.d目录下,varnishncsa脚本的完整内容如下所示:
- #!/bin/sh
- if [ "$1" = "start" ];then
- /usr/local/varnish/bin/varnishncsa -n /data/varnish/cache -f |/usr/sbin/rotatelogs /data/varnish/log/varnish.%Y.%m.%d.%H.log 3600 480 &
- elif [ "$1" = "stop" ];then
- killall varnishncsa
- else
- echo $0 "{start|stop}"
- fi
在这个脚本中,通过管道方式把日志导入到“rotatelogs”中,而rotatelogs是一个文件分割工具,它可以通过指定时间或者大小等方式来分割日志文件,这样就避免了日志文件过大造成的性能问题。
其中,“3600”是一个小时,也就是每个小时生成一个日志文件,“480”是一个时区参数,中国是第八时区,相对于UTC相差480分钟,如果不设置480这个参数,将导致日志记录时间和服务器时间相差8小时。关于rotatelogs命令用法,这里不再详细讲述。
通过对varnish日志的监控,可以知道varnish的运行状态和情况。
接着,将此脚本进行授权:
- [root@varnish-server ~]#chmod 755 /etc/init.d/varnishncsa
最后就可以通过如下方式,进行启动、关闭日志等操作了:
- [root@varnish-server ~]#/etc/init.d/varnishncsa {start|stop }
四、管理Varnish
1、查看varnish进程
通过上面章节的讲解,varnish已经可以启动起来了,执行如下命令可以查看varnish是否正常启动:
- [root@varnish-server ~]# ps -ef|grep varnish
- root 29615 1 0 00:20 pts/1 00:00:00 /usr/local/varnish/bin/varnishncsa -n /data/varnish/cache -f
- root 29616 1 0 00:20 pts/1 00:00:00 /usr/sbin/rotatelogs /data/varnish/log/varnish.%Y.%m.%d.%H.log 3600 480
- root 29646 1 0 00:21 ? 00:00:00 /usr/local/varnish/sbin/varnishd -P /var/run/varnish.pid -a 192.168.12.246:80 -T 127.0.0.1:3500 -f /usr/local/varnish/etc/vcl.conf -u varnish -g varnish -w 2,51200,10 -n /data/varnish/cache -s file,/data/varnish/cache/varnish_cache.data,4G
- varnish 29647 29646 0 00:21 ? 00:00:00 /usr/local/varnish/sbin/varnishd -P /var/run/varnish.pid -a 192.168.12.246:80 -T 127.0.0.1:3500 -f /usr/local/varnish/etc/vcl.conf -u varnish -g varnish -w 2,51200,10 -n /data/varnish/cache -s file,/data/varnish/cache/varnish_cache.data,4G
从命令执行结果可知,PID为29615和29616的进程是varnish的日志输出进程,而PID为29646的进程是varnishd的主进程,并且派生出了一个PID为29647的子进程。这点跟apache类似。
如果varnish正常启动的话,80端口和3500端口应该处于监听状态,通过如下命令可以查看:
- [root@varnish-server ~]# netstat -antl|grep 3500
- tcp 0 0 127.0.0.1:3500 0.0.0.0:* LISTEN
- [root@varnish-server ~]#netstat -antl|grep 80
- tcp 0 0 192.168.12.246:80 0.0.0.0:* LISTEN
- tcp 1 0 192.168.12.246:41782 192.168.12.26:80 CLOSE_WAIT
其中,80端口为varnish的代理端口,3500为varnish的管理端口。
2、查看varnish缓存效果与状态
可以通过浏览器访问对应的网页,查看varnish缓存的效果,如果varnish缓存成功的话,第二次打开网页的速度会明显比第一次快,但是这种方式并不能够完全说明问题,下面通过命令行方式,通过查看网页头来查看命中情况,操作如下:
- [root@varnish-server ~]# curl -I http://www.ixdba.net/a/mz/2010/0421/11.html
- HTTP/1.1 200 OK
- Server: Apache/2.2.14 (Unix) PHP/5.3.1 mod_perl/2.0.4 Perl/v5.10.1
- Last-Modified: Sat, 10 Jul 2010 11:25:15 GMT
- ETag: "5e850b-616d-48b06c6031cc0"
- Content-Type: text/html
- Content-Length: 24941
- Date: Fri, 09 Jul 2010 08:29:16 GMT
- X-Varnish: 1364285597
- Age: 0
- Via: 1.1 varnish
- Connection: keep-alive
- X-Cache: MISS from www.ixdba.net
#这里的"MISS"表示此次访问没有从缓存读取。
再次打开这个页面,查看网页头信息:
- [root@varnish-server ~]# curl -I http://www.ixdba.net/a/mz/2010/0421/11.html
- HTTP/1.1 200 OK
- Server: Apache/2.2.14 (Unix) PHP/5.3.1 mod_perl/2.0.4 Perl/v5.10.1
- Last-Modified: Sat, 10 Jul 2010 11:25:15 GMT
- ETag: "5e850b-616d-48b06c6031cc0"
- Content-Type: text/html
- Content-Length: 24941
- Date: Fri, 09 Jul 2010 08:30:35 GMT
- X-Varnish: 1364398612 1364285597
- Age: 79
- Via: 1.1 varnish
- Connection: keep-alive
- X-Cache: HIT from www.ixdba.net
#由“HIT”可知,第二次访问此页面时,是从缓存中读取内容了,也就是缓存命中。
缓存命中率的高低直接说明了varnish的运行状态和效果,较高的缓存命中率说明了varnish运行状态良好,web服务器的性能也会提高很多,反之,过低的缓存命中率说明varnish的配置可能存在问题,那么就需要进行调整,因此,从整体上了解varnish的命中率和缓存状态,对于优化和调整varnish至关重要。
varnish提供了一个varnishstat命令,通过它可以帮我们获得很多重要的信息。
下面是一个varnish系统的缓存状态:
- [root@varnish-server ~]#/usr/local/varnish/bin/varnishstat -n /data/varnish/cache
- Hitrate ratio: 10 100 113
- Hitrate avg: 0.9999 0.9964 0.9964
- 9990 68.92 49.70 Client connections accepted
- 121820 953.84 606.07 Client requests received
- 112801 919.88 561.20 Cache hits
- 68 0.00 0.34 Cache misses
- 2688 33.96 13.37 Backend conn. success
- 6336 1.00 31.52 Backend conn. reuses
- 2642 33.96 13.14 Backend conn. was closed
- 8978 29.96 44.67 Backend conn. recycles
- 6389 1.00 31.79 Fetch with Length
- 2630 32.96 13.08 Fetch chunked
- 444 . . N struct sess_mem
- 23 . . N struct sess
- 64 . . N struct object
- 78 . . N struct objectcore
- 78 . . N struct objecthead
- 132 . . N struct smf
- 2 . . N small free smf
- 3 . . N large free smf
- 6 . . N struct vbe_conn
- 14 . . N worker threads
- 68 1.00 0.34 N worker threads created
- 0 0.00 0.00 N queued work requests
- 1201 11.99 5.98 N overflowed work requests
- 1 . . N backends
- 4 . . N expired objects
- 3701 . . N LRU moved objects
- 118109 942.85 587.61 Objects sent with write
- 9985 71.91 49.68 Total Sessions
- 121820 953.84 606.07 Total Requests
这里需要注意的几个地方是:
“Client connections accepted”表示客户端向反向代理服务器成功发送HTTP请求的总数量。
"Client requests received"表示到现在为止,浏览器向反向代理服务器发送HTTP请求的累积次数,由于可能会使用长连接,所以这个值一般会大于“Client connections accepted”。
“Cache hits”表示反向代理服务器在缓存区中查找并且命中缓存的次数。
“Cache misses”表示直接访问后端主机的请求数量,也就是非命中数。
“N struct object”表示当前被缓存的数量。
“N expired objects”表示过期的缓存内容数量。
“N LRU moved objects”表示被淘汰的缓存内容个数。
五、管理varnish缓存内容
Varnish的一个显著优点是可以灵活的管理缓存内容,而管理缓存主要的工作是如何迅速有效的控制和清除指定的缓存内容,varnish清除缓存相对比较复杂,不过幸运的是,可以通过varnish的管理端口发送PURGE指令来清除不需要的缓存。
下面列出了清除缓存内容的命令格式:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url <regexp>
下面的命令可以列出最近清除的详细URL列表:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.list
举例如下:
(1)如果要清除http://www.example.com/a/2010.html的URL地址,可以执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url /a/2010.html
(2)批量清除类似http://www.example.com/a/b/s*.html的URL地址,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url ^/a/b/s.*$
(3)批量清除类似http://www.example.com/a/b/*.html的URL地址,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url ^/a/b.*$
(4)如果要清除所有缓存,可执行如下命令:
/usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.url ^.*$
(5)查看最近清除的详细URL列表
[root@varnish-server ~]# /usr/local/varnish/bin/varnishadm -T 192.168.12.246:3500 purge.list
0x2dc310c0 1278674980.497631 0 req.url ~ /zm/a/web/2010/0423/64.html
0x2dc31100 1278674964.851327 1 req.url ~ ^/zm/a/d.*$
除了通过linux命令行方式清理varnish缓存外,还可以通过telnet到管理端口的方式来清理缓存页面,例如:
- [root@varnish-server ~]#telnet 192.168.12.246 3500
- Trying 192.168.12.246...
- Connected to localhost.localdomain (192.168.12.246).
- Escape character is '^]'.
- 200 154
- -----------------------------
- Varnish HTTP accelerator CLI.
- -----------------------------
- Type 'help' for command list.
- Type 'quit' to close CLI session.
- purge.url /a/mz/2010/0421/11.html #这里是清除这个页面缓存
- 200 0
- purge.url ^/zm/a/d.*$ #这里是清除/zm/a/d/目录下所有以字母d开头的缓存页面
- 200 0
对于系统管理人员或者运维人员来说,时刻了解varnish命中率是至关重要的,虽然varnish给出了很详细的统计数据,但是统计的数据不是很直观,并且必须登录到varnish服务器才能查看,下面给出一个php程序,可以随时随地,并且非常清晰的了解varnish系统的命中率相关情况,程序如下:
- <?php
- // This is just a code snippet written by Jason "Foxdie" Gaunt, its not meant to be executed, it may work as-is, it may not.
- // I freely acknowledge this code is unoptimised but it has worked in practice for 6 months :)
- // Lets define our connection details
- $adminHost = "127.0.0.1"; // varnish服务器的IP地址
- $adminPort = "3500"; // varnish服务器管理端口
- // pollServer(str) - this function connects to the management port, sends the command and returns the results, or an error on failure
- function pollServer($command) {
- global $adminHost, $adminPort;
- $socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp"));
- if ((!socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, Array("sec" => "5", "usec" => "0"))) OR (!socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, Array("sec" => "5", "usec" => "0")))) {
- die("Unable to set socket timeout");
- }
- if (@socket_connect($socket, $adminHost, $adminPort)) {
- $data = "";
- if (!$socket) {
- die("Unable to open socket to " . $server . ":" . $port . "\n");
- }
- socket_write($socket, $command . "\n");
- socket_recv($socket, $buffer, 65536, 0);
- $data .= $buffer;
- socket_close($socket);
- return $data;
- }
- else {
- return "Unable to connect: " . socket_strerror(socket_last_error()) . "\n";
- }
- }
- // byteReduce(str) - this function converts a numeric value of bytes to a human readable format and returns the result
- function byteReduce($bytes) {
- // Terabytes
- if ($bytes > 1099511627776) {
- return round($bytes / 1099511627776) . "TB";
- }
- else if ($bytes > 1073741824) {
- return round($bytes / 1073741824) . "GB";
- }
- else if ($bytes > 1048576) {
- return round($bytes / 1048576) . "MB";
- }
- else if ($bytes > 1024) {
- return round($bytes / 1024) . "KB";
- }
- else {
- return $bytes . "B";
- }
- }
- // This is where our main code starts
- echo "<div class=\"inner\"><br />Statistics since last reset:<ul>";
- $stats = pollServer("stats");
- if (substr($stats, 0, 3) == "200") { // If request was legitimate
- // Clear all excessive white space and split by lines
- $stats = preg_replace("/ {2,}/", "|", $stats);
- $stats = preg_replace("/\n\|/", "\n", $stats);
- $statsArray = explode("\n", $stats);
- // Removes the first call return value and splits by pipe
- array_shift($statsArray);
- $statistics = array();
- foreach ($statsArray as $stat) {
- @$statVal = explode("|", $stat);
- @$statistics[$statVal[1]] = $statVal[0];
- }
- unset($stats, $statsArray, $stat, $statVal);
- // Start outputting statistics
- echo "<li>" . $statistics["Client connections accepted"] . " clients served over " . $statistics["Client requests received"] . " requests";
- echo "<li>" . round(($statistics["Cache hits"] / $statistics["Client requests received"]) * 100) . "% of requests served from cache";
- echo "<li>" . byteReduce($statistics["Total header bytes"] + $statistics["Total body bytes"]) . " served (" . byteReduce($statistics["Total header bytes"]) . " headers, " . byteReduce($statistics["Total body bytes"]) . " content)";
- // The following line is commented out because it only works when using file storage, I switched to malloc and this broke
- // echo "<li>" . byteReduce($statistics["bytes allocated"]) . " out of " . byteReduce($statistics["bytes allocated"] + $statistics["bytes free"]) . " used (" . round(($statistics["bytes allocated"] / ($statistics["bytes allocated"] + $statistics["bytes free"])) * 100) . "% usage)";
- }
- else {
- echo "Unable to get stats, error was: \"" . $stats;
- }
- echo "</ul></div>";
- ?>
将此php程序放到varnish服务器上,即可统计处当前varnish的命中率以及缓存状态,统计结果类似于下面的一个输出:
- Statistics since last reset:
- 63543 clients served over 584435 requests
- 98% of requests served from cache
- 4GB served (246MB headers, 4GB content)
在这个输出中,清晰的列出了浏览器请求总数、缓存命中率、缓存区中所有缓存内容的HTTP头信息长度和缓存内容的正文长度。根据这个结果判断,varnish的缓存效果还是很不错的,命中率很高。