Varnish 缓存服务器
1. varnish 的安装
1.1 安装依赖环境
yum install gcc gcc-c++ libstdc++-devel perl zlib zlib-devel automake automake libtool ncurses-devel libxslt pkgconfig make -y
1.2 安装pcre
unzip pcre-8.32.zip
cd pcre-8.32
./configure --prefix=/opt/pcre --enable-utf
make
make install
1.3 安装varnish
cd varnish-3.0.2
export echo=echo
export PKG_CONFIG_PATH=/opt/pcre/lib/pkgconfig
./configure --prefix=/opt/varnish --enable-dependency-tracking --enable-debugging-symbols --enable-developer-warnings
make
make install
mkdir /opt/varnish/conf
cp redhat/varnish.initrc /etc/init.d/varnish
cp redhat/varnish.sysconfig /opt/varnish/conf/varnish
cp redhat/varnish_reload_vcl /opt/varnish/conf/
2. 配置varnish
2.1 配置varnish启动脚本
vi /etc/init.d/varnish
#! /bin/sh
#
# varnish Control the Varnish Cache
#
# chkconfig: - 90 10
# description: Varnish is a high-perfomance HTTP accelerator
# processname: varnishd
# config: /etc/sysconfig/varnish
# pidfile: /var/run/varnishd.pid
### BEGIN INIT INFO
# Provides: varnish
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start:
# Default-Stop:
# Should-Start: $syslog
# Short-Description: start and stop varnishd
# Description: Varnish is a high-perfomance HTTP accelerator
### END INIT INFO
# Source function library.
. /etc/init.d/functions
retval=0
pidfile=/var/run/varnish.pid
exec="/opt/varnish/sbin/varnishd"
reload_exec="/opt/varnish/etc/varnish_reload_vcl"
prog="varnishd"
config="/opt/varnish/conf/varnish"
lockfile="/var/lock/subsys/varnish"
# Include varnish defaults
[ -e /opt/varnish/conf/varnish ] && . /opt/varnish/conf/varnish
start() {
if [ ! -x $exec ]
then
echo $exec not found
exit 5
fi
if [ ! -f $config ]
then
echo $config not found
exit 6
fi
echo -n "Starting Varnish Cache: "
# Open files (usually 1024, which is way too small for varnish)
ulimit -n ${NFILES:-131072}
# Varnish wants to lock shared memory log in memory.
ulimit -l ${MEMLOCK:-82000}
# $DAEMON_OPTS is set in /etc/sysconfig/varnish. At least, one
# has to set up a backend, or /tmp will be used, which is a bad idea.
if [ "$DAEMON_OPTS" = "" ]; then
echo "\$DAEMON_OPTS empty."
echo -n "Please put configuration options in $config"
return 6
else
# Varnish always gives output on STDOUT
daemon --pidfile $pidfile $exec -P $pidfile "$DAEMON_OPTS" > /dev/null 2>&1
retval=$?
if [ $retval -eq 0 ]
then
touch $lockfile
echo_success
echo
else
echo_failure
echo
fi
return $retval
fi
}
stop() {
echo -n "Stopping Varnish Cache: "
killproc -p $pidfile $prog
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
stop
start
}
reload() {
if [ "$RELOAD_VCL" = "1" ]
then
$reload_exec
else
force_reload
fi
}
force_reload() {
restart
}
rh_status() {
status -p $pidfile $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
configtest() {
if [ -f "$VARNISH_VCL_CONF" ]; then
$exec -f "$VARNISH_VCL_CONF" -C -n /tmp > /dev/null && echo "Syntax ok"
else
echo "VARNISH_VCL_CONF is unset or does not point to a file"
fi
}
# See how we were called.
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
restart
;;
configtest)
configtest
;;
*)
echo "Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
exit 2
esac
exit $?
2.2 配置varnish启动参数
vi /opt/varnish/conf/varnish
NFILES=131072
MEMLOCK=82000
DAEMON_OPTS="-a 10.10.37.165:80 \
-T 127.0.0.1:8000 \
-f /opt/varnish/etc/varnish/default.vcl \
-s malloc,512m"
3. 配置VCL
/opt/varnish/etc/varnish/default.vcl 配置如下:
# This is a basic VCL configuration file for varnish. See the vcl(7)
# man page for details on VCL syntax and semantics.
# Default backend definition. Set this to point to your content
# server.
# 定义主机健康检查
probe healthcheck {
.url = "/";
.interval = 60s;
.timeout = 1s;
.window = 8;
.threshold = 3;
.initial = 3;
.expected_response = 200;
}
# 定义abc后端服务器
backend abc1 {
.host = "10.151.20.65";
.port = "80";
.probe = healthcheck ;
}
backend abc2 {
.host = "10.151.20.75";
.port = "80";
.probe = healthcheck ;
}
# 定义directoer,主备的方法切换
director abc fallback {
{ .backend = abc1;}
{ .backend = abc2;}
}
# 定义def后端服务器
backend def1 {
.host = "10.151.20.44";
.port = "80";
.probe = healthcheck ;
}
backend def2 {
.host = "10.151.20.54";
.port = "80";
.probe = healthcheck ;
}
# 定义Director,主备的方法切换
director def fallback {
{ .backend = def1;}
{ .backend = def2;}
}
# 定义执行purge方法的访问控制列表
acl purgers {
"127.0.0.1";
"localhost";
}
# Below is a commented-out copy of the default VCL logic. If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
sub vcl_recv {
# 定义转发到相应的后端服务器
if (req.http.Host ~ "abc.example.corp" ) {
set req.backend = abc;
}
elsif (req.http.Host ~ "def.example.cn" || req.http.Host ~ "def.example.corp") {
set req.backend = def;
}
else {
error 408 "Hostname not found";
}
# 判断purge方法执行
if (req.request == "PURGE"){
if(!client.ip ~ purgers){
error 405 "Method not allowed";
}
}
# 记录源IP
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
# 将非常规请求执行pipe
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
if (req.request != "GET" && req.request != "HEAD") {
/* We only deal with GET and HEAD by default */
return (pass);
}
# 不缓存验证码
if (req.request == "GET" && req.url ~ "/auth/authcode.shtml$") {
return (pass);
}
# 只缓存def的图片
if (req.request == "GET" && req.http.Host ~ "def.example.*" && req.url ~ "\.(jpg|png|gif|swf|jpeg|ico|js|css)$") {
unset req.http.cookie;
}
# 直接转发动态请求
# if (req.request == "GET" && req.url ~ "^/app/") {
# return (pass);
# }
# if (req.http.Authorization || req.http.Cookie) {
# /* Not cacheable by default */
# return (pass);
# }
# 不缓存授权信息
if (req.http.Authorization ) {
/* Not cacheable by default */
return (pass);
}
return (lookup);
}
sub vcl_pipe {
# Note that only the first request to the backend will have
# X-Forwarded-For set. If you use X-Forwarded-For and want to
# have it set for all requests, make sure to have:
# set bereq.http.connection = "close";
# here. It is not set by default as it might break some broken web
# applications, like IIS with NTLM authentication.
return (pipe);
}
sub vcl_pass {
return (pass);
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
}
sub vcl_hit {
return (deliver);
}
sub vcl_miss {
return (fetch);
}
sub vcl_fetch {
set req.grace = 30m;
# if (beresp.http.Pragma ~ "no-cache" ||
# beresp.http.Cache-Control ~ "no-cache" ||
# beresp.http.Cache-Control ~ "private") {
# return (pass);
# }
# if (req.request = "GET" && req.http.Host ~ "def.example.cn" && req.url ~ "\.(png|bmp|jpeg|png|gif|jpg)$") {
# set beresp.ttl = 1d;
# set beresp.do_gzip = true;
# }
# 缓存html文件,压缩,缓存ttl为1d
if ( req.request == "GET" && req.url ~ "\.html$"){
set beresp.ttl = 1d;
set beresp.do_gzip = true;
}
# 缓存图片文件,压缩,缓存ttl为1d
if ( req.request == "GET" && req.url ~ "\.(jpg|png|gif|swf|jpeg|ico|js|css)$") {
set beresp.ttl = 1d;
set beresp.do_gzip = true;
}
return (deliver);
}
sub vcl_deliver {
return (deliver);
}
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>"} + obj.status + " " + obj.response + {"</title>
</head>
<body>
<h1>Error "} + obj.status + " " + obj.response + {"</h1>
<p>"} + obj.response + {"</p>
<h3>Guru Meditation:</h3>
<p>XID: "} + req.xid + {"</p>
<hr>
<p>Varnish cache server</p>
</body>
</html>
"};
return (deliver);
}
sub vcl_init {
return (ok);
}
sub vcl_fini {
return (ok);
}
4. varnish 缓存命中验证
可以看到接收到来自varnish的图片header 信息中包含 varnish字样