① 基本解读
1) nginx在2015年 '1.9.8版本'引入ngx_http_slice_module模块
2) slice模块'默认没有'编译nginx时,需要'显示'加参数--with-http_slice_module编译
3) nginx的ngx_http_slice_module模块是用来'支持Range回源'的
使用'背景':
1) 使用nginx作为反向代理并'缓存了上游响应'的时候
2) 如果'上游的响应文件'特别大,nginx去处理这样一个响应的时候'效率'就比较低下
3) 特别是'多个请求同时并发的请求'一个'没有缓存的大文件'的时候,'性能'是问题
nginx提供了slice模块,可以通过'range协议'把一个很大的响应分解为很多小的响应,来提升服务性能
客户端的请求必须有'range协议',具体表现为'Range请求头'
备注: 'Range'一般和'Cache缓存'结合使用,否则就'没有意义'了
③ slice指令
slice 模块是'分而治之'的思想
++++++++++ "缺点" ++++++++++
1) 当 'slice 配置 很小'的时候,会按照 slice 大小分成很'多个'子请求
2) 而这些个子请求并'不会马上释放[缓存]'自己的资源,可能会导致'文件描述符耗尽'等情况
⑤ slice模块的运行流程
++++++++++++ "解读" ++++++++++++
1、假定: nginx配置'slice 2m',目标是5m的test.mp4文件
1) 当我们发送一个'GET请求','不携带'Range头,默认就是读取'所有'
2) 我们在'后端的服务器'上会'看到3个'Range请求
3) 每个range请求的'请求范围'都是2M
4) 即第一个是0-2M,第二个是2-4M,第三个是4-6M
备注: 第一个字节位置是从'0'开始
++++++++++++++ "若干个解答" ++++++++++++++
问题1: 为什么'每次都是去后端取2MB范围'的片
解答: slice 2m; 这个'配置'产生的作用
问题2: 为什么向后端'发起了3个'range请求?
1) nginx一开始'并不知道'要发几个range'子请求'
2) 它会根据配置的'slice 2m;'
3) 先'发起一个2m'的range请求,这个请求返回的'Content-Range响应头'会给出文件总长度
Content-Range格式:bytes 开始字节位置-结束字节位置/文件大小 --> "重点"
4) 这样nginx就'知道'一共需要'发几个range请求'来取完所有内容
问题3:为什么'发到后端的子请求'也是Range请求?
解答: 回源的请求头'添加了Range' --> proxy_set_header Range $slice_range;
⑥ 对比实验理解Range
++++++++++++ 不使用slice模块,只使用'nginx的缓存' ++++++++++++
1) cache proxy里,有个'很棘手'的问题,就是range的'缓存和回源'问题
2) 上游返回了'完整'的响应,这是nginx做的优化:
[1]、虽然client只想访问了响应中的'一小部分'内容
[2]、但是'nginx代理'一次性获取'所有'的内容
[3]、client'后续'访问其中的'其它'字节,你就可以'直接使用缓存'了
3) 细节: 客户虽然获取'局部'内容,但是'nginx缓存'了'所有'文件内容
+++++++ "上游服务器的资源和日志查看" +++++++
++++++++++++ 使用nginx的'缓存'和'slice'模块 ++++++++++++
1) proxy_cache_key 必须'要有$slice_range'内插才知道是'对应范围'的字节
2) proxy_set_header Range $slice_range是'发送到上游'
3) nginx只需要'reload'即可
+++++++++ "客户端发出的Range和nginx转发的Range请求头关系" +++++++++
1) nginx发出'sub_request'子请求中的'Range请求'头的值是基于'slice size'配置重新整合
2) 而'不是'按照客户端的'Range请求头'的内容请求
3) nginx接收'多片'之后会'重新整合'出原始客户需要的'Range'请求头的内容
4) 举例说明:
[1]、文件大写'10m',nginx配置'slice 2m'、用户请求'Range [3m,5m]'的内容
[2]、nginx转发子请求的'Range'请求头的值$slice为'[2m,4m]'和'[4m,6m]'
[3]、nginx接收上游的'[2m,6m]'的内容会重新整合出'[3m,5m]'的内容发送给'客户端'
解读: 响应头Content-Length表示'对应字节大小';响应头Content-Range返回和请求'对应的范围'
1) Range是在 'HTTP/1.1'里新增的一个'请求头'字段域
2) 检查'服务端是否支持'Range
[1]、客户端'发起'请求
[2]、服务端收到后在'response的header中'如果有Accept-Ranges:bytes ,表示'支持Range'
[3]、响应头中的'Content-Length' 表示'返回传输数据字节'的大小
+++++++++++++++++++++++++++++"分割线"+++++++++++++++++++++++++++++
实验1: curl '模拟CDN的边缘节点','nginx'作为'源站',对资源进行'最终解释',不再向'上游'转发
结论: 'nginx'作为'静态'服务器支持'Range'分片
ngx_http_range_header_filter函数用来给客户端响应头中插入"Accept-Ranges:bytes"头
nginx断点续传功能代码浅析Range模块 过滤器模式关于Range的
实验2: curl '模拟CDN节点'开启Range回源,nginx作为'源站'
观察: '响应状态码'、'Range'请求头、'Content-Length'响应头、'Content-Range'响应头
⑧ curl -r参数解读
让客户端'使用range协议',cuel等价的'两种行为':
1) curl -r 0-2000
2) curl -H 'Range: bytes=0-2000'
补充: curl支持'区间'、'多区间'
nginx的slice模块'没有'处理'multiple range'类型的请求,'不支持'多range请求
例如: Range: bytes=2048-4095,4096-6143,6144-8191
nginx处理: 在开启slice模块时,nginx会直接'忽略多范围range'当成'完整文件'来处理
⑨ nginx的slice配置最佳实践
题外话: auth和slice模块都涉及'子请求','Range'是'HTTP1.1'引入的
location / {
slice 1m;
proxy_cache cache;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_http_version 1.1;
proxy_cache_valid 200 206 1h;
proxy_pass http://localhost:8000;
}
1) nginx为什么要'proxy_set_header Range $slice_range;'?
2) '$http_range'和'$slice_range'是否等价?
3) 如果'不'等价,'$slice_range'是不是每次'子请求'时候'动态'变化
实验1:
1) nginx'编译'对应的'slice'参数 --> --with-http_slice_module
2) curl模拟客户端,nginx节点模拟CDN节点,具备Range回源和Cache的能力,另一台nginx作为源站
3) 观察'代理nginx和源站nginx[重点]'日志中'$slice_range'的值,响应'状态码'
观察1: '源站nginx'收到几次子请求
观察2: 与'Range'相关'请求'头和'响应'头
角色: 模拟'CDN节点'的支持'Cache和Range'的'nginx'配置
+++++++++ "有趣的现象" +++++++++
1) nginx -t的时候,如果proxy_pass中的域名是'裸域名'用的是/etc/resolv.conf进行解析
2) 而如果'用变量'的时候,nginx -t'不会'报错,有用户请求的时候'才用resolver指令'进行解析
角色: 模拟'源站'的'nginx'配置
测试: 客户端'第一次'访问
观察1: 客户端的'请求'和'响应'内容
观察2: 模拟'CDN'节点的nginx节点的'access.log'日志和'Cache'缓存
说明: 理论上每个'cacahe_key'对应文件的内容应该是'512k',但是由于元数据等信息,比预期的大
cache_key文件名计算方式以及文件多出来的元数据的内容
观察3: 模拟'源站'的nginx节点的日志
结论: 作为'CDN节点'的'nginx'中的'$slice_range'是动态变化的
nginx-slice模块源码解析 nginx分片模块流程分析
⑩ 应用场景
场景1: 断点'续传'
'切片存储'的好处 ["断点续传的原理"]:
1) 每个'子请求'收到的数据都会形成一个'独立文件'
2) 这个文件就是通过'proxy_cache_key $uri$is_args$args$slice_range;'来定位的
3) 也就是说'文件跟key有绑定'关系
4) 这种将片'缓存为独立文件'的方式,还获得了一个'额外的优势'
5) 就是如果'某个片取源连接断掉[drop]',那么'前面已经缓存的片'依然有效
场景2: '多线程'下载
原理: 支持"多范围",类似 curl -i -H "Range: bytes=0-1,4-5" ,但是nginx'不支持'
If-Range请求头常用在断点续传中 nginx断点续传原理 案例讲解
⑪ Range头涉及的状态码
+++++++++++++ "Range请求的响应状态码" +++++++++++++
常见: 200、'206'、416,注意三者在Range请求的'含义'差异
1)206: 支持部分返回,将返回'指定部分'数据;
2)200: 不支持部分返回,将'从头开始完整返回'数据
3)416: 请求数据'范围不合法' --> "范围越界"
⑫ 参考链接
1) 'Range'是理解'CDN'的一个'重要'辅助知识点
2) 对于CDN来说,这个'slice模块'经常使用
Range、Content-Length 、Transfer-Encoding的区别
CDN为什么要求:客户源站更新资源后,必须在CDN强制刷新缓存 解决数据不一致问题
⑬ Range不生效原因
说明: '该小结'将'摘录'部分CDN中的内容
CDN'云厂商'共同点: 都是从源站分段获取'用户需要'的'部分资源'并缓存到CDN节点上