Range 请求与疯狂回源
对于一些较大的媒体资源,浏览器对其的加载方式可能是分片的,可能会在请求头中指定 Range,然后多线程下载。于是一个视频播放下来并不是只有一个视频请求,而是许许多多零碎的视频请求。
nginx 对 Range 的处理默认是不会 proxy_pass 到上游服务器的,所以即便用户请求一个 Range,CDN 向源站请求的也会是完整资源。那么,当客户端发起大量 Range 请求时,在 CDN 节点从源站加载到资源并缓存前,所有这些零碎的 Range 请求都会导致 CDN 节点向源站请求完整资源。
后果是什么?首先,客户端的请求变得非常慢;源站服务器的流量暴增。如果资源大的话,甚至会把源站服务器的带宽给占满。
其实不把 Range 传回源头站的做法是对的,如果 Range 传回去就变成对每个片段单独缓存。而客户端请求的片段位置是不确定的,那就会造成缓存命中率变低。
目前我也没有什么好办法解决这个问题,只是觉得对于大型资源,也许不应该采用自有源,而是在发布时主动推送到 CDN 节点上。
这让我想起了浏览器 GET 请求共用的问题。网页上也会有很多重复的资源,浏览器会对这些资源共用请求。所以即使页面上放了无数个 IMG 标签指向同一张图片浏览器也不会发起多余的请求。
要真正解决这个问题,也许应该对 nginx 的 upstream 模块做一波优化。