版权声明:本文由黄希彤   原创文章,转载请注明出处: 
文章原文链接:https://www.qcloud.com/community/article/668639001484812620

来源:腾云阁 https://www.qcloud.com/community

有一个朋友开发的手机app,把大量文件都保存在腾讯云COS上,然后通过CDN分发。
最近有一个特殊的需求,希望通过CVM来提供部分COS文件的访问。因为服务器用的是Nginx,所以事情也很简单:
1 到COS的管理页面上查询一下内网访问域名
Nginx反向代理腾讯云COS的一个坑-LMLPHP

2 给nginx增加一个标准的upstream配置,上游指向腾讯云COS的内网域名

Nginx反向代理腾讯云COS的一个坑-LMLPHP

照理说,配置好域名解析就可以开始工作了。但是一开始工作就出现很奇怪的现象:下载开始很快,随后变得很慢,最终有很大概率失败。

首先排除网络原因的可能性。登录服务器用wget通过访问本机localhost验证:
Nginx反向代理腾讯云COS的一个坑-LMLPHP
现象就是前面都下载的飞快,到了最后一部分就突然下载不动了。

打开nginx的error_log,发现了upstream timed out (Connection timed out)错误
Nginx反向代理腾讯云COS的一个坑-LMLPHP

再排除COS有问题的可能性:
Nginx反向代理腾讯云COS的一个坑-LMLPHP

现在问题就很诡异了:上游没有问题,经过反向代理后文件的前面一大部分也都没有问题,就是最后一小截文件要等待很久很久,并且发生了upstream timed out超时。

通过肥龙找到了熟悉nginx的ares同学协助抓包,才定位到了这个问题:

Nginx反向代理腾讯云COS的一个坑-LMLPHP

这里的UA是wget,wget默认使用的是http1.0协议。当前服务器使用的nginx是1.0.15这个比较古老的稳定版,还不支持 proxy_http_version 1.1这样的参数(要到1.1.4版本以后才支持)。所以也是采用http1.0协议代理了请求。

照理说innercos服务接到这样的请求应该按照http1.0的方式返回数据,但是我们看到服务器返回了 HTTP/1.1 200 OK 。也就是说不管客户端支持什么http版本cos服务总是用http1.1协议来工作。

http1.1有一个重要的特性是keep-alive,也就是说http数据传输完毕后TCP连接继续保持一段时间不断开,可以给后续的http请求重用。而http1.0的客户端原则上并不知道http1.1的这套原理。所以对于这个老版本的Nginx来讲,它收到完整的数据以后,看到TCP链接一直没有断开,以为upstream还有话说,就一直挂在那里,等上游继续送数据,直到上游连接超时,才在error_log里面记录一个timed out错误,然后断开下游的连接。

把proxy_buffering 关掉让上下游直接对上话可以绕过这个问题,但是有附带的损失。更好的办法是把nginx升级到1.1.4以上的版本,并且开启proxy_http_version 1.1 。
Nginx反向代理腾讯云COS的一个坑-LMLPHP

Nginx反向代理腾讯云COS的一个坑-LMLPHP

Nginx反向代理腾讯云COS的一个坑-LMLPHP

至此圆满解决。

总结一下,腾讯云COS的后台服务假设客户端都支持http1.1协议,对http1.0协议没有做很好的兼容,而腾讯云CVM提供的带Nginx的系统镜像里面的Nginx版本又有点儿老旧了,proxy还只能工作在http1.0上,导致了这个问题的出现。

05-11 14:10