我有一个系统通过四个负载平衡的 varnish 缓存访问多个后端服务。大约 0.1% 的请求被截断,因为 varnish 返回了不正确的内容长度标头。此错误发生在所有缓存和各种后端。
Varnish 配置为不缓存任何没有有效缓存控制标头的内容,并且不会缓存这些特定请求。客户端不会发送 Accept-Encoding 标头,因此 Varnish 会从后端请求经过 gzip 压缩的响应,并向客户端发送未压缩的版本。
从 varnishlog 来看,所有后端请求看起来都一样:
BerespStatus 200
BerespReason OK
BerespHeader Content-Encoding: gzip
BerespHeader Content-Length: 1001
BerespHeader Content-Type: application/json
BerespHeader Date: Fri, 08 Feb 2019 14:59:06 GMT
BerespHeader Vary: Accept-Encoding
TTL RFC 0 10 0 1549637947 1549637947 1549637946 0 0 cacheable
VCL_call BACKEND_RESPONSE
TTL VCL 120 10 0 1549637947 cacheable
TTL VCL 120 10 0 1549637947 uncacheable
VCL_return deliver
Filters testgunzip
Storage malloc Transient
Fetch_Body 3 length stream
Gzip u F - 1001 3792 80 7906 7944
BackendReuse 54 default
Length 1001
我相信该行Gzip u F - 1001 3792 80 7906 7944
表明 1001 字节的压缩响应解压缩后为 3792 字节。
有三种不同类型的响应。约 50% 将内容长度设置为 3792:
VCL_call RECV
ReqHeader Surrogate-Capability: key=ESI/1.0
VCL_return hash
VCL_call HASH
VCL_return lookup
HitMiss 1052359 119.885211
VCL_call MISS
VCL_return fetch
Link bereq 1052362 fetch
Timestamp Fetch: 1549633459.720553 0.004765 0.004765
RespProtocol HTTP/1.1
RespStatus 200
RespReason OK
RespHeader Content-Encoding: gzip
RespHeader Content-Length: 1000
RespHeader Content-Type: application/json
RespHeader Date: Fri, 08 Feb 2019 13:44:19 GMT
RespHeader Vary: Accept-Encoding
RespHeader Age: 0
RespHeader Via: 1.1 varnish (Varnish/6.1)
VCL_call DELIVER
RespHeader X-Cache: MISS
RespHeader X-Cache-Hits: 0
VCL_return deliver
Timestamp Process: 1549633459.720567 0.004779 0.000014
RespUnset Content-Encoding: gzip
RespHeader Accept-Ranges: bytes
RespUnset Content-Length: 1000
RespHeader Content-Length: 3792
Gzip U D - 1001 3792 80 7906 7944
大约 50% 没有内容长度标头,但使用传输编码分块:
Same as above except
...
RespUnset Content-Length: 1000
RespHeader Transfer-Encoding: chunked
Gzip U D - 1001 3792 80 7906 7944
还有 0.1% 的情况是因为内容长度不正确而导致客户端崩溃:
...
RespUnset Content-Length: 1001
RespHeader Content-Length: 208
Gzip U D - 1001 3792 80 7906 7944
有人知道造成这种情况的原因吗?对调试的下一步有什么建议吗?
我的 VCL 不对内容长度标头执行任何操作。我正在运行 varnish 6.1(我正在考虑降级到稳定版本 6.0.2,但尚未尝试)
编辑:
降级到 6.0.2 并且仍然看到同样的问题。
编辑2:
我已经使用命令开关禁用了 varnish 将请求升级到 gzip -p "http_gzip_support=off"
,这样就解决了这个问题,但代价是非压缩请求在到达后端时仍然不是压缩的,但现在这样已经足够了。