故事是这样的: 一合作小伙伴使用的 IIS6.0 搭建的wap站点,并使用了国内某家CDN,我们自己的 squid 缓存CDN的内容再返回给其他客户(晕没?)。之前一直好好的,近期这家小伙伴运维给IIS6的css,js等静态文件加了压缩。问题来了,我们的 squid 无法从CDN上获取css,js等文件,导致页面加载异常,这跟 varnish 有毛线关系?且往下看。
分析其原因是我们的 squid2.7 对http1.1支持的不完整,客户端必须要传入[Accept-Encoding: “gzip, deflate”] 才能正常访问,测试时使用浏览器均和一正常访问,但是wget和curl等命令默认不行,必须传Accept-Encoding才行。而且无论是对方的CDN还是源站均有这样的问题。
网上这样的解决办法:
squid2.7版本: 在 squid.conf 中增加:
cache_vary on acl IIS rep_header Server ^Microsoft-IIS broken_vary_encoding allow IIS
IIS6.0修改如下配置:
C:\Windows\system32\inetsrv\metabase.xml HcNoCompressionForHttp10="TRUE" HcNoCompressionForProxies="TRUE" HcDoDynamicCompression="TRUE" 上面的“TRUE”都改成“FALSE”
上述配置还是无法完美解决这样的问题。于是想到了要单独给这家小伙伴配置一个反向代理。
首先想到了 nginx,测试了一番之后无法实现,主要是 nginx 的 proxy_pass 方式仍然使用 http1.0 向后通讯。于是转向了使用 Varnish,目前最主要的问题就是对方使用了CDN,并且不让我们直接回原站取数据,这反向代理要去CDN取数据,开什么国际玩笑?人艰不拆啊!
不过决定还是要一试,这次使用了Varnish4.0.1,最近稳定版本,官网地址
下面是安装及配置步骤,重点是varnish 4.x版本支持多后端服务器,可采用不容算法,并支持健康检查,或许能满足万一一台CDN节点挂掉导致页面无法取回的现象。
Varnish安装
rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.0.el6.rpm yum install varnish 或者手动下载rpm包: http://repo.varnish-cache.org/redhat/varnish-4.0/el6/x86_64/varnish/varnish-4.0.1-1.el6.x86_64.rpm
版本:
# /usr/sbin/varnishd -V varnishd (varnish-4.0.1 revision 4354e5e) Copyright (c) 2006 Verdens Gang AS Copyright (c) 2006-2011 Varnish Software AS
启动参数配置:
配置文件地址
centos/RHEL: /etc/sysconfig/varnish
Ubuntu:/etc/default/varnish
# cat /etc/sysconfig/varnish | grep -v ^#| grep -v ^$ NFILES=131072 MEMLOCK=82000 NPROCS="unlimited" RELOAD_VCL=1 VARNISH_VCL_CONF=/etc/varnish/default.vcl VARNISH_LISTEN_PORT=80 VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 VARNISH_SECRET_FILE=/etc/varnish/secret VARNISH_MIN_THREADS=50 VARNISH_MAX_THREADS=1000 VARNISH_THREAD_TIMEOUT=120 VARNISH_STORAGE_SIZE=256M VARNISH_STORAGE="malloc,${VARNISH_STORAGE_SIZE}" VARNISH_TTL=120 DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ -f ${VARNISH_VCL_CONF} \ -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ -t ${VARNISH_TTL} \ -p thread_pool_min=${VARNISH_MIN_THREADS} \ -p thread_pool_max=${VARNISH_MAX_THREADS} \ -p thread_pool_timeout=${VARNISH_THREAD_TIMEOUT} \ -u varnish -g varnish \ -S ${VARNISH_SECRET_FILE} \ -s ${VARNISH_STORAGE}"
启动方式:
# /etc/init.d/varnish Usage: /etc/init.d/varnish {start|stop|status|restart|condrestart|try-restart|reload|force-reload} 或者手动启动: /usr/sbin/varnishd -P /var/run/varnish.pid -a :80 -f /etc/varnish/default.vcl -T 127.0.0.1:6082 -t 120 -p thread_pool_min=50 -p thread_pool_max=1000 -p thread_pool_timeout=120 -u varnish -g varnish -S /etc/varnish/secret -s malloc,256M /usr/sbin/varnishd -f /etc/varnish/default.vcl -s malloc,1G -T 127.0.0.1:2000 -a 0.0.0.0:80
varnish vcl 配置文件:
# cat /etc/varnish/default.vcl vcl 4.0; import directors; acl localnetwork { "localhost"; "192.168.0.0"/20; } backend foo{ .host = "foo.bar.com"; .port = "80"; } backend mysite01{ #.host = "domain.mysite.com"; .host = "112.90.172.80"; .port = "80"; } backend mysite02{ #.host = "domain.mysite.com"; .host = "116.114.22.98"; .port = "80"; } backend mysite03{ #.host = "domain.mysite.com"; .host = "123.125.19.13"; .port = "80"; } sub vcl_init { new vdir = directors.round_robin(); vdir.add_backend(mysite01); vdir.add_backend(mysite03); vdir.add_backend(mysite03); } sub vcl_recv { if (req.http.host ~"^foo.bar.com$") { set req.http.host= "foo.bar.com"; set req.backend_hint = metest; } elsif (req.http.host ~"^domain.mysite.com$") { set req.http.host= "domain.mysite.com"; set req.backend_hint = vdir.backend(); } else { return(synth(404, "Unknown virtual host.")); #error 404 "Unknown virtual host"; } if (req.http.Accept-Encoding) { if(req.http.Accept-Encoding ~ "gzip") { set req.http.Accept-Encoding = "gzip"; } elsif (req.http.Accept-Encoding ~ "deflate" ) { set req.http.Accept-Encoding = "deflate"; } else { #remove req.http.Accept-Encoding; unset req.http.Accept-Encoding; } } if (req.method == "PURGE") { if (!client.ip ~ localnetwork) { return(synth(405,"Not allowed.")); } # jump to hit/miss return (purge); } }
上述几个IP地址均为CDN地址,做了rr方式的轮询。
varnishstat:
Uptime mgt: 5+07:54:07 Uptime child: 5+07:54:04 NAME CURRENT CHANGE AVERAGE AVG_10 AVG_100 AVG_1000 MAIN.uptime 460444 1.00 1.00 1.00 1.00 1.00 MAIN.sess_conn 435 0.00 . 0.00 0.00 0.00 MAIN.client_req 423 0.00 . 0.00 0.00 0.00 MAIN.cache_miss 3 0.00 . 0.00 0.00 0.00 MAIN.backend_conn 3 0.00 . 0.00 0.00 0.00 MAIN.backend_toolate 1 0.00 . 0.00 0.00 0.00 MAIN.backend_recycle 3 0.00 . 0.00 0.00 0.00 MAIN.fetch_length 3 0.00 . 0.00 0.00 0.00 MAIN.pools 2 0.00 . 2.00 2.00 2.00 MAIN.threads 100 0.00 . 100.00 100.00 100.00 MAIN.threads_created 100 0.00 . 0.00 0.00 0.00 MAIN.n_backend 6 0.00 . 6.00 6.00 6.00 MAIN.n_expired 3 0.00 . 3.00 3.00 3.00 MAIN.s_sess 435 0.00 . 0.00 0.00 0.00 MAIN.s_req 423 0.00 . 0.00 0.00 0.00 MAIN.s_fetch 3 0.00 . 0.00 0.00 0.00 MAIN.s_synth 420 0.00 . 0.00 0.00 0.00 MAIN.s_req_hdrbytes 34959 0.00 . 0.00 0.00 0.00 MAIN.s_resp_hdrbytes 87407 0.00 . 0.00 0.00 0.00 MAIN.s_resp_bodybytes 173550 0.00 . 0.00 0.00 0.00 MAIN.sess_closed 390 0.00 . 0.00 0.00 0.00 MAIN.sess_readahead 1 0.00 . 0.00 0.00 0.00 MAIN.backend_req 3 0.00 . 0.00 0.00 0.00 MAIN.n_vcl 1 0.00 . 0.00 0.00 0.00 MAIN.bans 1 0.00 . 1.00 1.00 1.00 MAIN.vmods 1 0.00 . 1.00 1.00 1.00 MAIN.n_gunzip 2 0.00 . 0.00 0.00 0.00 MGT.uptime 460447 1.00 1.00 1.09 1.09 1.09 SMA.s0.c_req 4 0.00 . 0.00 0.00 0.00 SMA.s0.c_bytes 46736 0.00 . 0.00 0.00 0.00 SMA.s0.c_freed 46736 0.00 . 0.00 0.00 0.00 SMA.s0.g_space 268435456 0.00 . 268435456.00 268435456.00 268435456.00 SMA.Transient.c_req 2 0.00 . 0.00 0.00 0.00 SMA.Transient.c_bytes 131744 0.00 . 0.00 0.00 0.00 v MAIN.uptime
再次测试,发现wget,curl中已经不用再传 http header Accept-Encoding了。