SLB(Serverless Load Balancing) : GCP(Google Cloud Platform)中的 SLB(Serverless Load Balancing)是一种无服务器的负载均衡服务。
线上希望通过接入提高 B 国家用户的访问体验,所以在 B 国家新增了一个谷歌云服务的接入点
在测试中发现,转发的延迟达到了 680ms,远远的超过了 134ms(假如连接不复用情况下,那么 2rtt 也只是 268ms),经过排查,发现响应体约 90K,tcp 响应得分开 90 多个包传输,由于 tcp 各种问题,所以总时间拖长了(后续再总结)
但是
- A 国家数据中心请求是能够正常压缩,相同的数据压缩后只有 8KB
- B 国家数据中心请求压缩异常
问题排查
排查 Nginx
这个配置 gzip_min_length
的参数值为正整数,单位为字节,也可用 k 表示千字节,比如写成 1024 与 1k 都可以,效果是一样的,表示当资源大于1k时才进行压缩,资源大小取响应头中的 Content-Length
进行比较,经测试如果响应头不存在 Content_length
信息,该限制参数对于这个响应包是不起作用的;另外此处参数值不建议设的太小,因为设的太小,一些本来很小的文件经过压缩后反而变大了,官网没有给出建议值,在此建议1k起,因为小于1k的也没必要压缩,并根据实际情况来调整设定。
而它的默认值是 20 字节。 如果为 0,那就全部都压缩。
而我们设置的是 1000 字节,也就是如果请求返回的 Content-Length
大于 1000, 那么就会启用 gzip 压缩并返回。 如果小于 1000, 那么就会正常返回。
事实上上面第二张图之所以没有返回的时候用 gzip 压缩,就是因为 response 返回的 Content-Length
小于 1000, 所以不会启用 gzip 压缩返回。
通过抓包对比两个数据中心的请求
发现谷歌 SLB 会在代理的请求增加以下 Header 标明是 http 的
Via: 1.1 google
通过查阅 nginx 配置,发现有个可疑的配置
gzip_proxied: nginx 默认是不会对于来自代理服务器的请求就行压缩的,原因可参考 what are the options for the gzip proxied for,简而言之
- 客户端支持的压缩协议不同,假如把响应 gzip 放在代理服务器上,代理服务器还是得解压了再按客户端支持的协议重新下发,或者客户端不支持或者不期望压缩。
- 对于某些内容,得基于未压缩的文件进行处理,例如视频的播放或者断点下载,客户端发起 range 请求,服务端依然得基于未压缩的内容进行处理。
所以 Nginx 对于有 via 头的,默认则不压缩是合理的
对于该情况,由于对外的都是 api 接口,不存在 cache 的情况,所以添加以下配置就解决了
web 到处充斥着压缩,那么 nginx 是怎么判断什么时候需要处理的?tomcat 呢? 各个工具间是怎么保证不产生冲突的。
先总结
- nginx 提供了一系列的 gzip_ 前缀的配置控制是否压缩,tomcat 由于角色是 web 容器,所以提供的选项只有 3 个,连 compress level 都不提供。
- 在配置启用压缩的前提下,还会检查 Content-Encoding 是否存在 gzip 值,对于 nginx 会更加的详细,会判断多额外的边界条件,例如 gzip, q=0 也禁用。从这点上看,nginx+tomcat 的这种主流架构,尽管同时启用了 gzip,都不会产生冲突。
- http 针对压缩有 accept-encoding(针对请求)以及 Content-Encoding(针对响应),所以服务器间压缩前判断是否 Content-Encoding 已经标明该内容以及压缩了,则不进行重复压缩。
源码解析
nginx 源码
ngx_http_gzip_filter_module.c
ngx_http_core_module
Tomcat 源码
可配置的选项 相对较少
- compressibleMimeType
- compression
- compressionMinSize
基本就是允许什么 content-type 的进行压缩,启用压缩的大小是多少
org.apache.coyote.http11.Http11Processor
以 http1.1 协议为例,主要逻辑为,以下只说明压缩后会改变了什么 http 的头部