后端机器返回错误的gzip数据导致varnish出现503错误

近期,笔者维护的varnish服务器,不定期出现503错误,按照以往经验,调整超时时间、请求和响应header 正文缓冲区大小,均无解。

然后,只有从varnish本身的行为入手,在varnish机器上启动varnishlog 观察日志,发现有一处异常

ObjHeader      Content-Length: 164

Fetch_Body     3 length stream

Gzip           Gunzip error: -3 (incorrect header check)

FetchError     Invalid Gzip data: incorrect header check

Gzip           u F - 2 0 0 0 0

从字面上看,是gzip数据格式导致的,然后就反复猜想,有可能是源服务器返回了错误的gzip数据,使用curl访问源服务器:

curl -i -H "Accept-Encoding:gzip" -H "Host:域名"  http://源服务器ip/文件路径

输出结果:

后端机器返回错误的gzip数据导致varnish出现503错误_第1张图片

根据源服务器的响应header Content-Encoding:gzip 明确告诉我们,正文部分已经使用gzip压缩,但是观察输出,却很诡异,输出的却是明文的未压缩过的内容,但最后一行,全是空字符,最后一个字符,倒是很像是gzip压缩过的内容,说明服务器欺骗了我们,虽然告诉我们内容是gzip压缩过的,但实际上却是不正确的gzip结果。


然后,我们再尝试获取不压缩的内容:

curl -i  -H "Host:域名"  http://源服务器ip/文件路径

后端机器返回错误的gzip数据导致varnish出现503错误_第2张图片

这次服务器返回了没有压缩过的内容,明显是正确的了。

分析结果:

  1. 默认情况下,无论客户端是否支持gzip, varnish在请求源服务器时,会自动增加Accept-Encoding:gzip指令,期待获取压缩内容

  2. varnish取到结果后,会根据vcl_backend_response事件中的beresp.do_gzip = true/false指令,决定是否把内容gzip压缩后缓存起来(显然压缩后缓存,会节省大量内存或磁盘资源),如果这个指令没有设置,则使用原因内容缓存,不作压缩任何压缩处理。

  3. 无论源服务器是否支持gzip压缩,无论缓存内容是否已经gzip压缩,只要客户端支持gzip压缩,varnish会返回gzip的内容。另一面,如果客户端不支持gzip压缩,varnish会将缓存的gzip压缩过的内容进行解压,再发送给客户端。

  4. varnish是设计就是以最佳性能为考虑的,所以默认是启用gzip压缩的。

知道这几个原理后,如果源机器返回了非法的gzip内容,我们可以用以下任何一个方法处理:

  1.  让源机器返回正确的gzip内容,或禁止源机器gzip压缩。

  2. 让varnish在请求源机器时,期望获取不压缩内容

  3. 彻底禁止掉varnish的所有gzip压缩功能(向客户端发送不压缩的内容——无论客户端是否支持gzip;  请求源服务器时,期望获取不压缩内容)

以上三个方法,任选 一个,即可解决这个问题:

第2条的配置文件方法(在vcl文件中设置):

sub vcl_backend_fetch {

        unset bereq.http.Accept-Encoding;

        return (fetch);

}

第3条解决方法:

varnishd启动时,使用-p http_gzip_support=off 完全关闭掉gzip支持,如果是使用yum安装,可在/et/sysconfig/varnish文件中指定

如果varnish已经启动,不允许重启,则可在运行时修改它, 使用 varnishadm 命令,进入命令行界面,查看参数:

param.show

可直接输入help, 查看扩展的指令, 使用以下命令全局关闭gzip支持:

param.set http_gzip_support off

经过这样处理后,偶尔返回503错误的问题得到了解决。

你可能感兴趣的:(后端机器返回错误的gzip数据导致varnish出现503错误)