神折腾:用varnish处理gzip,并为CDN提供反向代理

神折腾:用varnish处理gzip,并为CDN提供反向代理
varinish

故事是这样的: 一合作小伙伴使用的 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了。