背景
线上希望通过接入提高B国家用户的访问体验,所以在B国家新增了一个谷歌云服务的接入点
在测试中发现,转发的延迟达到了680ms,远远的超过了134ms(假如连接不复用情况下,那么2rtt也只是268ms),经过排查,发现响应体约90K,tcp响应得分开90多个包传输,由于tcp各种问题,所以总时间拖长了(后续再总结)
但是
- A国家数据中心请求 是能够正常 压缩,相同的数据压缩后只有8KB
- B国家数据中心请求 压缩异常
问题排查
排查Nginx
1 | gzip on; |
通过抓包对比两个数据中心的请求
发现谷歌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的情况,所以添加以下配置就解决了
1 | gzip_proxied: any |
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
1 | static ngx_int_t |
ngx_http_core_module
1 |
|
Tomcat源码
tomcat针对压缩,可配置的选项相对较少
- compressibleMimeType
- compression
- compressionMinSize
基本就是允许什么content-type的进行压缩,启用压缩的大小是多少
org.apache.coyote.http11.Http11Processor
以http1.1协议为例,主要逻辑为,以下只说明压缩后会改变了什么http的头部
1 | if (useCompression) { |