一  ngx_http_slice模块

①  基本解读

1) nginx在2015年 '1.9.8版本'引入ngx_http_slice_module模块

2) slice模块'默认没有'编译nginx时,需要'显示'加参数--with-http_slice_module编译

3) nginx的ngx_http_slice_module模块是用来'支持Range回源'的

nginx stick工作原理 nginx slice_nginx

②  slice引入的背景

使用'背景':

  1) 使用nginx作为反向代理并'缓存了上游响应'的时候

  2) 如果'上游的响应文件'特别大,nginx去处理这样一个响应的时候'效率'就比较低下

  3) 特别是'多个请求同时并发的请求'一个'没有缓存的大文件'的时候,'性能'是问题

nginx提供了slice模块,可以通过'range协议'把一个很大的响应分解为很多小的响应,来提升服务性能

客户端的请求必须有'range协议',具体表现为'Range请求头'

备注: 'Range'一般和'Cache缓存'结合使用,否则就'没有意义'了

③  slice指令

nginx stick工作原理 nginx slice_CDN_02

slice 模块是'分而治之'的思想

++++++++++ "缺点" ++++++++++

 1) 当 'slice 配置 很小'的时候,会按照 slice 大小分成很'多个'子请求

 2) 而这些个子请求并'不会马上释放[缓存]'自己的资源,可能会导致'文件描述符耗尽'等情况

nginx stick工作原理 nginx slice_Range_03

④  $slice_range内置变量

nginx stick工作原理 nginx slice_缓存_04

⑤  slice模块的运行流程

nginx stick工作原理 nginx slice_缓存_05

nginx stick工作原理 nginx slice_缓存_06

++++++++++++  "解读"  ++++++++++++

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 stick工作原理 nginx slice_缓存_07

+++++++ "上游服务器的资源和日志查看"  +++++++

nginx stick工作原理 nginx slice_nginx stick工作原理_08

nginx stick工作原理 nginx slice_CDN_09

nginx stick工作原理 nginx slice_nginx stick工作原理_10

++++++++++++ 使用nginx的'缓存'和'slice'模块 ++++++++++++

nginx stick工作原理 nginx slice_CDN_11

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]'的内容发送给'客户端'

nginx stick工作原理 nginx slice_nginx stick工作原理_12

解读: 响应头Content-Length表示'对应字节大小';响应头Content-Range返回和请求'对应的范围'

nginx stick工作原理 nginx slice_CDN_13

⑦  RFC文档之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'分片

nginx stick工作原理 nginx slice_Range_14

nginx stick工作原理 nginx slice_CDN_15

ngx_http_range_header_filter函数用来给客户端响应头中插入"Accept-Ranges:bytes"头

nginx断点续传功能代码浅析Range模块  过滤器模式关于Range的

实验2: curl '模拟CDN节点'开启Range回源,nginx作为'源站'

观察: '响应状态码'、'Range'请求头、'Content-Length'响应头、'Content-Range'响应头

nginx stick工作原理 nginx slice_CDN_16

nginx stick工作原理 nginx slice_Range_17

nginx stick工作原理 nginx slice_nginx stick工作原理_18

⑧  curl -r参数解读 

让客户端'使用range协议',cuel等价的'两种行为':

 1) curl -r 0-2000

 2) curl -H 'Range: bytes=0-2000' 

补充: curl支持'区间'、'多区间'

nginx stick工作原理 nginx slice_Range_19

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;
}

nginx stick工作原理 nginx slice_缓存_20

1) nginx为什么要'proxy_set_header Range $slice_range;'?

2) '$http_range'和'$slice_range'是否等价?

3) 如果'不'等价,'$slice_range'是不是每次'子请求'时候'动态'变化

proxy_set_header关于Range的说明

nginx stick工作原理 nginx slice_缓存_21

实验1:

1) nginx'编译'对应的'slice'参数  --> --with-http_slice_module

2) curl模拟客户端,nginx节点模拟CDN节点,具备Range回源和Cache的能力,另一台nginx作为源站

3) 观察'代理nginx和源站nginx[重点]'日志中'$slice_range'的值,响应'状态码'

  观察1: '源站nginx'收到几次子请求

  观察2: 与'Range'相关'请求'头和'响应'头

nginx stick工作原理 nginx slice_nginx stick工作原理_22

nginx stick工作原理 nginx slice_nginx_23

角色: 模拟'CDN节点'的支持'Cache和Range'的'nginx'配置

+++++++++  "有趣的现象"  +++++++++

 1) nginx -t的时候,如果proxy_pass中的域名是'裸域名'用的是/etc/resolv.conf进行解析

 2) 而如果'用变量'的时候,nginx -t'不会'报错,有用户请求的时候'才用resolver指令'进行解析

nginx stick工作原理 nginx slice_Range_24

角色: 模拟'源站'的'nginx'配置

nginx stick工作原理 nginx slice_CDN_25

测试: 客户端'第一次'访问

观察1: 客户端的'请求'和'响应'内容

nginx stick工作原理 nginx slice_缓存_26

观察2: 模拟'CDN'节点的nginx节点的'access.log'日志和'Cache'缓存

说明: 理论上每个'cacahe_key'对应文件的内容应该是'512k',但是由于元数据等信息,比预期的大

nginx stick工作原理 nginx slice_CDN_27

nginx stick工作原理 nginx slice_nginx_28

 cache_key文件名计算方式以及文件多出来的元数据的内容

观察3: 模拟'源站'的nginx节点的日志

结论: 作为'CDN节点'的'nginx'中的'$slice_range'是动态变化的

nginx stick工作原理 nginx slice_nginx stick工作原理_29

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断点续传原理  案例讲解

nginx stick工作原理 nginx slice_nginx stick工作原理_30

⑪   Range头涉及的状态码

+++++++++++++ "Range请求的响应状态码" +++++++++++++

常见: 200、'206'、416,注意三者在Range请求的'含义'差异

1)206: 支持部分返回,将返回'指定部分'数据;

2)200: 不支持部分返回,将'从头开始完整返回'数据

3)416: 请求数据'范围不合法' --> "范围越界"

nginx stick工作原理 nginx slice_CDN_31

⑫   参考链接

1) 'Range'是理解'CDN'的一个'重要'辅助知识点

2) 对于CDN来说,这个'slice模块'经常使用

Range、Content-Length 、Transfer-Encoding的区别

给CDN配置Range回源

CDN 如何实现range回源

Nginx:作为缓存,支持Range回源

slice和子请求、Range的关系

http协议之Range

if-range引起的cdn分片缓存问题

slice[0.8m,3.5m]案例理解

腾讯CDN的分片回源设置

nginx对静态文件开启缓存

Nginx Slice 模块支持 multi-ranges

CDN为什么要求:客户源站更新资源后,必须在CDN强制刷新缓存  解决数据不一致问题

缓存刷新和缓存预热的区别

nginx stick工作原理 nginx slice_nginx_32

⑬   Range不生效原因

源服务器对Range请求支持不完善

说明: '该小结'将'摘录'部分CDN中的内容

CDN'云厂商'共同点: 都是从源站分段获取'用户需要'的'部分资源'并缓存到CDN节点上

阿里云配置Range回源

nginx stick工作原理 nginx slice_Range_33

nginx stick工作原理 nginx slice_Range_34

华为云配置CDN回源 

nginx stick工作原理 nginx slice_Range_35

nginx stick工作原理 nginx slice_CDN_36