使用nginx分片功能提升缓存效率,支持可拖拽式播放视频

您所在的位置:网站首页 NGINX缓存头 使用nginx分片功能提升缓存效率,支持可拖拽式播放视频

使用nginx分片功能提升缓存效率,支持可拖拽式播放视频

2023-12-19 08:38| 来源: 网络整理| 查看: 265

Nginx的slice模块可以将一个请求分解成多个子请求,每个子请求返回响应内容的一个片段,让大文件的缓存更有效率。

HTTP Range请求

HTTP客户端下载文件时,如果发生了网络中断,必须重新向服务器发起HTTP请求,这时客户端已经有了文件的一部分,只需要请求剩余的内容,而不需要传输整个文件,Range请求就可以用来处理这种问题。

如果HTTP请求的头部有Range字段,如下面所示:

Range: bytes=9437184-16165716

表示客户端请求文件的第9437184到第16165716个字节,这时服务器只会响应文件的这部分内容,响应的状态码为206,表示返回的是响应的一部分。如果服务器不支持Range请求,仍然会返回整个文件,这时状态码仍是200。

如果没有slice的话,可能服务器需要让14773740这么多字节全部缓冲完之后再统一返回给客户端/浏览器,比如这段:

192.168.40.72 - - [27/Dec/2021:18:25:33 +0800] "GET /e61bfa1a48a4764b6a653568aff6aff.mp4 HTTP/1.1" 206 14773740 "http://192.168.32.98/e61bfa1a48a4764b6a653568aff6aff.mp4" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" 192.168.40.72 - - [27/Dec/2021:18:26:34 +0800] "GET /e61bfa1a48a4764b6a653568aff6aff.mp4 HTTP/1.1" 206 16534500 "http://192.168.32.98/e61bfa1a48a4764b6a653568aff6aff.mp4" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" 192.168.40.72 - - [27/Dec/2021:18:28:09 +0800] "GET /e61bfa1a48a4764b6a653568aff6aff.mp4 HTTP/1.1" 206 21319452 "http://192.168.32.98/e61bfa1a48a4764b6a653568aff6aff.mp4" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" 192.168.40.72 - - [27/Dec/2021:18:38:13 +0800] "GET /e61bfa1a48a4764b6a653568aff6aff.mp4 HTTP/1.1" 206 83516688 "http://192.168.32.98/e61bfa1a48a4764b6a653568aff6aff.mp4" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"

如果开启了slice,设置分片大小为1m,那么你可能会看到,刚才的请求被分割为1M,或者小于1M的分片多个请求回来:

192.168.38.85 - - [28/Dec/2021:17:22:50 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" 192.168.38.85 - - [28/Dec/2021:17:22:52 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" 192.168.38.85 - - [28/Dec/2021:17:22:54 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" 192.168.38.85 - - [28/Dec/2021:17:22:56 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" 192.168.38.85 - - [28/Dec/2021:17:22:58 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" 192.168.38.85 - - [28/Dec/2021:17:23:11 +0800] "GET /resources/20211228/1889261312/downloadzip/c1f382848f2040d99932f7dc09c786.mp4?type=online HTTP/1.0" 206 1048576 "https://rtest-bj02.qsh1.cn/rec/page?id=c1f382848f2040d99932f7dc09c786&v=2" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"

nginx源码安装配置slice

nginx 1.9.8及其以上版本才支持slice。当在编译时添加了--with-http_slice_module,那么slice模块的相关配置就会启用。

首先我们来看下如何安装支持slice的nginx:

创建一个目录 /home/nginx_sourcecode/ 然后进入到目录中

如果你需要支持mp4在线播放

(下载 nginx_mod_h264_streaming)

wget http://h264.code-shop.com/download/nginx_mod_h264_streaming-2.2.7.tar.gztar -zxvf nginx_mod_h264_streaming-2.2.7.tar.gz

接下来下载nginx:

wget http://nginx.org/download/nginx-1.20.2.tar.gztar -zxvf nginx-1.20.2.tar.gz

cd nginx-1.20.2

重点来了,开始配置编译选项:

./configure --with-http_sub_module --with-http_flv_module --add-module=../nginx_mod_h264_streaming-2.2.7 --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_slice_module --with-http_ssl_module --with-http_mp4_module

配置好之后,你可能会报错:

../nginx_mod_h264_streaming-2.2.7/src/mp4_reader.c:526:22: error: variable ‘configuration_version’ set but not used [-Werror=unused-but-set-variable]

unsigned int configuration_version;

不要紧,你修改obj/Makefile,关闭警告提错误提示,同时关闭debug信息:

CFLAGS = -pipe -O -W -Wall -Wpointer-arith -Wno-unused-parameter -D_LARGEFILE_SOURCE -DBUILDING_NGINX

当然你在配置的过程中也可能还会报错:

make[1]: *** [objs/addon/src/ngx_http_h264_streaming_module.o] Error 1 make[1]: Leaving directory `/home/mock/BUILD_ROOT/BUILD/nginx-0.8.38′ make: *** [build] Error 2 解决办法:

vim nginx_mod_h264_streaming-2.2.7/src/ngx_http_streaming_module.c 将如下几行注释

/* TODO: Win32 */

if (r->zero_in_uri)

{

return NGX_DECLINED;

}

Slice原理

接下来就该说下slice的原理:

Nginx的slice模块是通过挂载filter模块来起作用的,处理流程如下所示

每次取源时都会携带Range头部,

第一次取源请求前1m内容,如果响应在1m以内,或者源服务器不支持Range请求,返回状态码为200,这时会直接跳过slice模块。

在body_filter中向客户端发送得到的当前的分片,然后检查是否到达文件末尾,如果没有则生成一个子请求,子请求会向源服务器请求下一个分片,依次循环。

客户端向nginx请求一个10M文件,nginx进行4m的切片,整个过程大概是

1.客户端向nginx请求10M

2.nginx发起第一个切片(主请求)请求range:0-4194303

3.第一个切片(主请求)请求的内容全部发给客户端后,在slice模块的body_filter发起第二个切片(子请求),请求range: 4194304-8388607

4.第二个切片(子请求)请求的内容完全发完給客户端后,切回主请求

5.主请求在slice模块的body_filter发起第三个切片(子请求),请求range: 8388608-12582911

6.第三个切片(子请求)请求的内容(8388608-10485759)完全发完給客户端后,切回主请求

7.主请求在slice模块的body_filter判断已经将10M的文件发給客户端,不再进行slice的模块处理

Range的范围

请求中的Range范围可能会超过文件的大小,如第一次取源时,Nginx并不知道实际文件的大小,所以Nginx请求时总是按照分片的大小设置Range范围,如slice设置为1m,那么第一次取bytes=0-1048575,如果文件不足1m,响应状态吗为200,表示不需要分片。如果超过1m,第二次取源时Range字段为bytes=1048576-2097171,即使这时可以知道文件实际大小。

线上使用时就遇到过一次源服务器对Range请求支持不完善的问题,文件大小为1.5m,第一次取源状态码为206,返回1m内容,第二次取源使Range字段为bytes=1048576-2097171,但是文件不足2m,源服务器发现这个范围超过了文件大小,所以返回了整个文件,状态码为200,这时Nginx就不能理解了,直接报错中断了响应。

开始以为是Nginx的问题,然后查看了下RFC文档,发现有解释这种情况

A client can limit the number of bytes requested without knowing the size of the selected representation. If the last-byte-pos value is absent, or if the value is greater than or equal to the current length of the representation data, the byte range is interpreted as the remainder of the representation (i.e., the server replaces the value of last-byte-pos with a value that is one less than the current length of the selected representation).

大致意思是说,如果请求的分片的后一个偏移超过了文件的实际大小,服务器应该返回剩余的部分内容。这个问题应该是源服务器的实现并没有按照RFC文档的要求。

slice配置

一般在产线环境,你可以使用cdn来当作代理服务器,并开通分片下载功能,通过cdn回到源服务器的时候,在源服务器配置分片大小。

接下来我提供下部分代理服务器的切片配置:

worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format sudops_logs '$remote_addr - $remote_user [$time_local] "$request" "$request_body" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for "$content_length" "$http_content_length" "$sent_http_content_length"'; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; proxy_cache_path /home/nginx_cache/ levels=1:2 keys_zone=cache:100m inactive=300s max_size=5g; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; slice 2m; proxy_cache cache; proxy_cache_key $uri$is_args$args$slice_range; proxy_set_header Range $slice_range; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_cache_valid 200 206 304 301 302 10d; proxy_pass http://192.168.32.98/; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }

可以看到代理服务器的分片大小为2M,并且使用了缓存,至于为什么要使用缓存,我将在下一篇文章介绍。

那么回源服务器的配置:

worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format sudops_logs '$remote_addr - $remote_user [$time_local] "$request" "$request_body" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for "$content_length" "$http_content_length" "$sent_http_content_length"'; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; # proxy_cache_path /home/gaoke/nginx_cache/ levels=1:2 keys_zone=cache:100m inactive=300s max_size=5g; server { listen 80; server_name localhost; #charset koi8-r; #针对mp4文件进行分片下载,当然如果你需要对flv文件支持分片,也可以加入路由规则 location ~\.mp4 { root html; slice 1m; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } # another virtual host using mix of IP-, name-, and port-based configuration # #server { # listen 8000; # listen somename:8080; # server_name somename alias another.alias; # location / { # root html; # index index.html index.htm; # } #} # HTTPS server # #server { # listen 443 ssl; # server_name localhost; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # location / { # root html; # index index.html index.htm; # } #} }

经过这样的配置,测试会发现你在线观看一个mp4的游戏视频,本来需要

Range回源是指客户端通知源站服务器只返回部分内容,以及部分内容的范围。这对于较大文件的分发加速有很大帮助。开启Range回源功能,可以减少回源流量消耗,并且提升资源响应时间。

需要源站支持range请求,即对于http请求头中包含 Range 字段,源站能够响应正确的206文件分片。

Range回源

具体描述

示例

开启

该参数可以请求回源站。此时源站需要依据 Range 的参数,响应文件的字节范围。同时CDN节点也会向客户端响应相应字节范围的内容。

客户端向CDN请求中含有range:0-100,则源站端收到的请求中也会含有range:0-100这个参数。并且源站响应给CDN节点,然后CDN节点响应给客户端的就是范围是0-100的一共101个字节内容。

关闭

CDN上层节点会向源站请求全部的文件,并且由于客户端会在收到Range定义的字节后自动断开http链接,请求的文件没有缓存到CDN节点上。最终导致缓存的命中率较低,并且回源流量较大。

客户端向CDN请求中含有range:0-100,则server端收到的请求中没有range这个参数。源站响应给CDN节点完整文件,但是CDN节点响应给客户端的就是101个字节,但是由于连接断开了,会导致该文件没有缓存到CDN节点上。

说明

需要源站支持range请求,即对于http请求头中包含 Range 字段,源站能够响应正确的206文件分片。

视频拖拽播放

拖拽播放功能是指:在视频点播场景中,如果用户拖拽播放进度时,客户端会向服务器端发送类似 http://www.test.com/test.flv?start=10 的URL请求。此时,服务器端会向客户端响应从第10字节的前一个关键帧(如果start=10不是关键帧所在位置)的数据内容。

开启该功能,CDN节点可以支持此项配置,可以在响应请求时直接向client响应从第10字节的前一个关键帧(如果start=10不是关键帧所在位置)(FLV格式)或第10s(MP4格式)开始的内容。

注意事项

需要源站支持range请求,即如果http请求头中包含 Range 字段,源站需要能够响应正确的206文件分片。

目前支持文件格式有:MP4和FLV。

文件类型

meta信息

start参数

举例

MP4

站视频的meta信息必须在文件头部,不支持meta信息在尾部的视频。

start参数表示的是时间,单位是s,支持小数以表示ms(如start=1.01,表示开始时间是1.01s),CDN会定位到start所表示时间的前一个关键帧(如果当前start不是关键帧)。

请求http: //domain/video.mp4?start=10就是从第10秒开始播放视频。

FLV

源站视频必须带有meta信息。

start参数表示字节,CDN会自动定位到start参数所表示的字节的前一个关键帧(如果start当前不是关键帧)。

对于http: //domain/video.flv,请求http:// domain/video.flv?start=10就是从第10字节的前一个关键帧(如果start=10不是关键帧所在位置)开始播放视频。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3