背景介绍:
通常Web服务器都会通过gzip压缩来减少用户下载的流量,提高页面打开速度。
gzip压缩分为两种,http1.0压缩和http1.1压缩,这两种压缩的压缩方法和response header都一样,只是客户端和服务器通讯的http协议不同。
Squid2.7之前,是不支持http1.1的。在2.7版本开始,有限支持http1.1。从3.0版本开始,才完整的支持http1.1。但是因为squid3是完全重构的,很多2.7的功能并没有加到3.0当中,所以squid3并没有被大规模的应用在生产系统中,基本上都还是使用squid2.6或2.7来进行内容加速,所以需要搞定Squid支持各种Web服务器的HTTP1.0 GZIP压缩。
一、压缩分析
Squid能否正确的处理gzip,完全取决于realserver会否发送正确的Vary:头部。一般来说,反向代理环境里,自己能控制realserver。
而采用Apache这样的标准web服务器,可配置mod_deflate让它发送正确的Vary:头部。这个头部的作用,就是指示squid,应该根据客户端的请求方式不同,返回不同的压缩或非压缩目标。
浏览器请求squid上的某个目标,假设该目标在squid上有压缩过的缓存,该缓存同时包括一个"Vary:"头部(按照RFC 2616协议,对压缩过的内容Apache必须返回该头部给squid)。
Squid会根据缓存里的Vary头部的值和请求头部进行匹配,如果请求头部里包含了Accept-Encoding相应值,则squid返回压缩过的目标给浏览器。相反,如果请求头部里没有包含Accept-Encoding字段(通常是http/1.0方式),则squid会将请求转发给 realserver。按照标准,Squid不允许发送压缩过的目标拷贝给不接受Encoding的浏览器。
Squid的请求到了realserver,mod_deflate返回非压缩的内容给Squid。这个响应也包含Vary头部,但不是压缩的。 squid拿到这个响应后,更新自己的缓存(squid的缓存目标存储结构是以url为key的哈希,就是同一个url下只能存储一份cache目标),并将响应返回给客户端。
下一次如果客户的请求又包含了Accept-Encoding字段,squid会根据缓存目标的Vary头部,再去realserver取一份压缩的内容返回给客户端,并更新自己的缓存。
所以,在上述机制下,squid对gzip的兼容没有问题。但是,这里有2个明显的问题:
1. 对某个cache住的目标,一个http/1.0请求可能会导致squid强制更新其缓存。但接下来的另一个http/1.1请求又会导致squid再次更新缓存。这就极大的降低了cache命中率。
2. 某些客户端,如IE6及以下,如果发送http/1.0的请求,realserver会返回没有压缩过的内容,同时包含一个Vary:头部。这些客户端不能处理这个头部,结果就导致目标无法下载。这是IE的bug,我们做不了什么。但碰到这种情况,用户会投诉你。
这实际上取决于squid是否支持http/1.1.squid对http/1.1的兼容性代码还在开发之中.不过squid-2.7版本在这方面已做了不少工作.
如果只想配置squid作为反向代理,那么编译安装最新版的squid-2.7(该版本已包含部分http/1.1协议的补丁),在squid.conf的http_port指令后加多一个关键字http11即可,如:
http_port 80 accel vhost http11 defaultsite=www.mytest.com
这样squid就基本兼容encoding了,可以在apache上配置mod_deflate来使用gzip压缩.
不过这种情况对http/1.0的客户端可能有点问题.要完全兼容http/1.0,需要配置下apache的mod_rewrite,基于 Accept-Encoding头部进行rewrite.如果客户端声称接受encoding,那么就使用mod_deflate来压缩内容.如果客户端不接受encoding,那么rewrite规则返回302,指示客户端跳转到另一个目录.该目录不过是前述mod_deflate目录的一个符号链接, 但针对该目录没有配置mod_deflate进行压缩.这样就可解决http/1.0客户端的问题
二、具体配置
1、squid配置
A,将cache_vary设置成on。使squid能够缓存带有vary头的内容
B,将broken_vary_encoding设置成all。squid.conf.default中,这个参数的示例是
acl apache rep_header Server ^Apache
broken_vary_encoding allow apache
2、realserver对于squid压缩的支持
要squid缓存代理完美处理压缩问题,就必须由realserver提供必要的支持
A、realserver是nginx
Nginx默认不支持http1.0协议通信压缩,支持http1.1,这样需要我们修改一下配置文件,具体操作步骤如下:
1. 打开nginx.conf配置文件找到gzip on刚配置好的nginx服务此选项是被注释掉的,将其打开后,默认支持http1.1,不支持http1.0
2. 怎样设置能使得http1.0支持gzip压缩,需要手动添加配置如下:
gzip on; #打开gzip压缩
gzip_http_version 1.0; #允许http1.0协议压缩
gzip_min_length 1000; #压缩的最小字节(可以不设置)
gzip_buffers 4 8k;
gzip_types text/plain application/x-javascript text/css text/html application/xml; #压缩类型
gzip_vary on; #开启vary头
设置完毕后保存,将其nginx服务重启一下,测试就可以了
B、realserver是apache
Apache 默认就支持http1.0协议通信压缩,不需要特定配置,但是要制定那些文件类型压缩需要修改配置文件,具体如下:
以apache2.2.3版本为例:
1. 首先查找mod_deflate.c库
将安装包解压后进入/usr/local/src/httpd-2.2.3/modules/filters目录下
2. 然后安装mod_deflate模块
/usr/local/apache/bin/apxs -i -c -a mod_deflate.c
3. 配置mod_deflate
编辑/usr/local/apache/conf/http.conf找到LoadModule deflate_module modules/mod_deflate.so将其模块打开
4. 设置制定文件类型,然后保存重启服务
5. 完毕后需要将相关文件进行添加vary头信息,然后重启网站,就可以实现通过代理压缩的功能.
三、压缩后影响
解决 Accept-Encoding 不一致造成的多份缓存问题