在分享本案例前,我们先来简要回顾下range请求相关知识点。
The Range 是一个请求头部,告知服务器返回文件的哪一部分。在一个Range头部中,可以一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。如果服务器返回的是范围响应,需要使用206 Partial Content 状态码。假如所请求的范围不合法,那么服务器会返回416 Range Not Satisfiable状态码,表示客户端错误。服务器允许忽略 Range 头部,从而返回整个文件并响应状态码200。
Range 请求头格式
Range: bytes=start-end
示例:
Range: bytes=10- :第11个字节到文件末尾的数据
Range: bytes=40-100 :第41个字节到第101个字节之间的数据
Range 响应头格式
Content-Range
示例
Content-Range: bytes 0-9/3103
Content-Length: 10
Last-Modified: Sun, 01 Dec 2020 05:14:15 GMT
即服务器响应了前(0-9)个即10字节的数据,该资源一共有(3103)个字节大小。Last-Modified表示资源最近修改的时间(分段下载时要注意这个东西,因为如果修改了,分段下载可能就要重新下载了)
问题描述:
客户反馈下载文件http://3qys.com.cn/13338141.apk时突然中断。
原因分析:
1、curl测试复现到现象,如下所示,8M的文件,下载到5M就断开连接了。
curl -voa 'http://3qys.com.cn/13338145.apk'
2、分析该异常访问的日志发现,该文件的回源请求是以多个206分片的形式,但客户端并未请求分片,这是为何?查看该域名的配置,有开启range回源,即客户端请求完整文件,CDN侧回源也会按照配置的分片大小发起range请求。
另外,从日志可以看到,该文件的0-5M部分CDN节点直接以缓存响应,5M后的部分未缓存命中需回源拉取,但此时触发了“长度或者mtime校验失败”的报错。
从该报错可以推测,该文件有发生变更。我们可以通过比对LM来验证下。
从复现到异常的截图可以看到,源站Last-Modified为Sun, 06 Dec 2020 05:14:15 GMT。此时,我们可以直接测试源站,看LM是否有更新。如下图,源站响应Last-Modified: Sun, 06 Dec 2020 05:23:42 GMT。即我们之前的猜测得到了印证。
原因总结:
域名开启了分片回源,CDN之前有缓存部分内容,后源站文件有更新,节点在回源拉取无缓存的内容时,校验mtime不一致,判断文件有更新,为了避免缓存到错误文件从而主动断开。(腾讯云CDN在该场景断开后,会主动清除之前旧文件的分片缓存)
ps:CDN侧的断开逻辑是合理的,因为mtime校验发现变化,说明源站文件有更新。若CDN侧不断开,会导致之前拉取到分片和文件更新后拉取到的分片无法合并成一个文件,或者即便合成一个文件也无法正常访问。
解决方案:
源站文件更新后,客户侧需要及时通过腾讯云控制台或者调用api接口提交url刷新。
客户侧建议:
1、小文件建议关闭分片回源
2、大文件建议开启分片回源,且需保证源站能支持range请求