nginx proxy_cache 缓存配置详解


Posted in Servers onMarch 31, 2021

前言:

由于本人工作原因,涉及到网络直播领域,其中视频的回放下载,涉及到了一些视频下载方面的技术。针对于一个完整视频的下载,目前市面上的主流做法是,先将整个视频流切片,存储到文件服务器中,在用户需要观看回放视频时。通过一个视频回源服务器,去文件服务器中逐个请求切片,返回给用户播放。

今天着重探讨的是关于回源服务器缓存的配置以及合理的缓存策略。

通过给回源服务器配置缓存的案例,详细讲解一整套缓存配置机制,并且可沿用到其他任何缓存配置场景中。

今天的讲解分为四点:

  • 回源服务器的工作是啥为啥
  • 需要给回源服务器加缓存
  • 如何配置缓存
  • 如何针对业务场景配置完备的缓存机制

回源服务器的工作:

回源服务器在下面叙述中简称:源站 如图所示,在文件下载的过程中,横跨在cdn与文件服务器之间,作为下载枢纽。

nginx proxy_cache 缓存配置详解

源站架构:源站是nginx+php的webserver架构,如图所示:

nginx proxy_cache 缓存配置详解

但如果源站只是简单的收到请求,然后下载资源,再返回,势必会存在以下几点不够优化的问题:

1、cdn可能存在多次回源现象

2、源站对同一资源的多次下载,存在网络流量带宽浪费,以及不必要的耗时。

所以为了优化这些问题,需要给源站做一层缓存。缓存策略采用nginx自带的proxy_cache模块。

proxy_cache原理:

proxy_cache模块的工作原理如图所示:

nginx proxy_cache 缓存配置详解 

如何配置proxy_cache模块

在nginx.conf文件中添加如下代码:

http{
  ......
  proxy_cache_path/data/nginx/tmp-test levels=1:2 keys_zone=tmp-test:100m inactive=7d max_size=1000g;
}

代码说明:

proxy_cache_path 缓存文件路径

levels 设置缓存文件目录层次;levels=1:2 表示两级目录

keys_zone 设置缓存名字和共享内存大小

inactive 在指定时间内没人访问则被删除

m ax_size 最大缓存空间,如果缓存空间满,默认覆盖掉缓存时间最长的资源。

当配置好之后,重启nginx,如果不报错,则配置的proxy_cache会生效

查看   proxy_cache_path / data/ nginx / 目录, 会发现生成了 tmp -test 文件夹。

如何使用proxy_cache

在你对应的nginx vhost server配置文件中添加如下代码:

location /tmp-test/ {
 proxy_cache tmp-test;
 proxy_cache_valid 200 206 304 301 302 10d;
 proxy_cache_key $uri;
 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_passhttp://127.0.0.1:8081/media_store.php/tmp-test/;
}

配置项介绍: Proxy_cache tmp -test 使用名为 tmp -test 的对应缓存配置

proxy_cache_valid  200 206 304 301 302 10d; 对httpcode为200…的缓存10天

proxy_cache_key $uri  定义缓存唯一key,通过唯一key来进行hash存取

proxy_set_header  自定义http header头,用于发送给后端真实服务器。

proxy_pass   指代理后转发的路径,注意是否 需要 最后的 /

到这里,最基本的 proxy_cache 功能就配置成功了。当uri成功匹配到该location,则proxy_cache就会生效。

添加proxy_cache之后,请求过程的变化:

1、第一次访问:

nginx proxy_cache 缓存配置详解 

第一次访问,proxy_cache并没有找到对应的缓存文件(未命中缓存MISS),所以当第一次请求完成的同时,proxy_cache会保持缓存:

2、保存缓存,如图所示:

nginx proxy_cache 缓存配置详解 

3、同一个url第二次访问,当同一个文件再次到达源站,proxy_cache就会找到其对应的缓存文件(命中缓存HIT)直接返回给请求端,无需再执行php程序,如图所示:

nginx proxy_cache 缓存配置详解 

提出疑问:

到此,就完成了最基本的proxy_cache配置和访问过程介绍,但是最基本的配置,往往无法满足我们的业务需求,我们往往会提出以下几点疑问和需求:

  1. 需要主动清理缓存文件
  2. 写入路径为一块磁盘,如果磁盘打满该怎么解决?
  3. 如何让源站支持断点续传,以及断点续传的缓存策略
  4. 如果请求端 range 请求(分片下载)一个大资源,同样的uri,如何区别请求?
  5. 还需要告诉请求端,资源的过期时间
  6. 日志统计,如何配置命中与不命中字段,如何做统计?

面对以上疑问,我们一个一个解决。

问题一:主动清理缓存

采用:nginx  proxy_cache_purge 模块 ,该模块与proxy_cache成对出现,功能正好相反。 设计方法:在nginx中,另启一个server,当需要清理响应资源的缓存时,在本机访问这个server。 例如: 访问 127.0.0.1:8083/tmp-test/TL39ef7ea6d8e8d48e87a30c43b8f75e30.txt 即可清理该资源的缓存文件。 配置方法:

location /tmp-test/ {
        allow 127.0.0.1; //只允许本机访问
        deny all; //禁止其他所有ip
        proxy_cache_purge tmp-test $uri; //清理缓存
    }

proxy_cache_purge:缓存清理模块 tmp-test:指定的key_zone $uri:指定的生成key的参数 proxy_cache_purge缓存清理过程,如图所示:

nginx proxy_cache 缓存配置详解 

问题二:缓存文件强磁盘打满该怎么办?

由于写入路径为一个单一目录,只能写入一块磁盘。一块磁盘很快就会被打满,解决该问题有如下两种方法:

1、将多块磁盘做磁盘阵列? 缺点是:减小了实际的存储空间。

2、巧妙得运用proxy_cache_path的目录结构,由于levels=1:2,这导致缓存文件的目录结构为两层,每层目录名,都是由hash函数生成。如图所示:

nginx proxy_cache 缓存配置详解 

总共含有16*16*16=4096个文件目录。对该一级目录进行软连接,分别将0-f软连接到你所需要的指定磁盘目录上,如图所示:

nginx proxy_cache 缓存配置详解 

通过软链的方法,实现:将不同盘下的目录作为真正存放数据的路径,解决了多盘利用,单盘被打满的问题。

问题三:支持range(断点续传)

添加上缓存代理之后,客户端发起的range请求将会失效,如下图所示:

nginx proxy_cache 缓存配置详解 

导致range参数无法传递到下一级的原因如下:

当缓存代理转发http请求到后端服务器时,http header会改变,header中的部分参数,会被取消掉。其中range参数被取消,导致,后端nginx服务器没有收到range参数,最终导致这个分片下载不成功。所以需要对代理转发的header进行配置。 例如:

location /tmp-test/ {
        proxy_cache tmp-test;
        proxy_cache_valid 200 206 304 301 302 10d;
        proxy_cache_key $uri;
        proxy_set_header Range $http_range;
        proxy_pass http://127.0.0.1:8081/media_store.php/tmp-test/;
}

红色部分的含义:将http请求中的range值($http_range)放到代理转发的http请求头中作为参数range的值。

问题四,当支持range加载后,proxy_cache_key,则需要重新配置:

如果请求端 Range请求(分片下载)一个大资源,同样的uri,proxy cache如何识别资源对应的key。 由于nginx配置为:proxy_cache_key $uri,用uri作为key 所以当请求为普通请求和range请求时,都是同样的uri作为key。proxy_cache将有可能导致错误返回。如下图所示:

nginx proxy_cache 缓存配置详解 

解决方法如下: 修改proxy_cache_key ,配置proxy_cache_key $http_range$uri; 这样就能解决:key唯一性。可以避免不管是正常请求还是不同的range请求,第一次获取的内容和之后获取的缓存内容都不会出现异常。

问题五:如何配置-返回过期时间

需要通过返回过期时间来指定请求端,哪些资源需要缓存,哪些资源不缓存,

 

参数 正常请求 range请求
返回过期时间 返回 不返回

为了防止请求端将分片资源当做完整资源缓存起来,我们需要对正常请求,返回过期时间;对range请求, 不返回过期时间。 解决该问题,通过对nginx配置即可解决:

location /media_store.php {
   fastcgi_pass  127.0.0.1:9000;
   fastcgi_index media_store.php;
   fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
   include    fastcgi_params;
   if ( $http_range = ''){
     expires 2592000s;
   }
}

在proxy_pass代理之后的location中加入对$http_range的判断,expires 表示过期时间。 2592000s指缓存过期时间。

问题七:缓存命中情况如何在http头中体现,以及在nginx日志中查看

解决方法:

 利用nginx $upstream_cache_status变量:该变量代表缓存命中的状态,

如果命中,为HIT;如果未命中,为MISS

在返回nginx server配置中添加:

add_header Nginx-Cache "$upstream_cache_status";

在nginxlog中添加:

log_format combinedio …$upstream_cache_status;

http返回head截图:

nginx proxy_cache 缓存配置详解 

nginx log日志截图:

nginx proxy_cache 缓存配置详解 

总结:

整个一套完备的缓存策略就介绍到此,这套方案中不仅实现了基本的缓存配置,还解决了实际场景应用中会遇到的,磁盘扩展,缓存清理,断点续传,缓存过期时间,缓存命中提示等问题,只要将这套方案灵活运用,不管是再复杂的场景,基本都能满足需求。以上都是我在工作中爬过的坑,不断完善总结出的结果,希望对读者能有帮助。

到此这篇关于nginx proxy_cache 缓存配置详解的文章就介绍到这了,更多相关nginx proxy_cache 缓存 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Servers 相关文章推荐
nginx如何将http访问的网站改成https访问
Mar 31 Servers
Mac环境Nginx配置和访问本地静态资源的实现
Mar 31 Servers
Nginx反向代理配置的全过程记录
Jun 22 Servers
nginx配置虚拟主机的详细步骤
Jul 21 Servers
图文详解Nginx版本平滑升级方案
Sep 15 Servers
Nginx虚拟主机的搭建的实现步骤
Jan 18 Servers
Minikube搭建Kubernetes集群
Mar 31 Servers
阿里云日志过滤器配置日志服务
Apr 09 Servers
nginx搭建NFS网络文件系统
Apr 14 Servers
教你如何用cmd快速登录服务器
Jun 10 Servers
windows server 2012安装FTP并配置被动模式指定开放端口
Jun 10 Servers
ubuntu20.04虚拟机无法上网的问题及解决
Dec 24 Servers
Nginx搭建rtmp直播服务器实现代码
Mar 31 #Servers
nginx 反向代理之 proxy_pass的实现
Mar 31 #Servers
nginx location中多个if里面proxy_pass的方法
Mar 31 #Servers
nginx配置proxy_pass中url末尾带/与不带/的区别详解
Mar 31 #Servers
Linux安装Nginx步骤详解
Nginx 502 Bad Gateway错误原因及解决方案
Nginx访问日志及错误日志参数说明
Mar 31 #Servers
You might like
解析Win7 XAMPP apache无法启动的问题
2013/06/26 PHP
学习php设计模式 php实现工厂模式(factory)
2015/12/07 PHP
php生成0~1随机小数的方法(必看)
2017/04/05 PHP
PHP curl 或 file_get_contents 获取需要授权页面的方法
2017/05/05 PHP
JavaScript 学习小结(适合新手参考)
2009/07/30 Javascript
JavaScript中的一些定位属性[图解]
2010/07/14 Javascript
js函数获取html中className所在的内容并去除标签
2013/09/08 Javascript
javascript实现检验的各种规则
2015/07/31 Javascript
JQuery悬停控制图片轮播——代码简单
2015/08/05 Javascript
Node.js+Express配置入门教程
2016/05/19 Javascript
AngularJS表单详解及示例代码
2016/08/17 Javascript
如何使用vuejs实现更好的Form validation?
2017/04/07 Javascript
使用Angular CLI生成 Angular 5项目教程详解
2018/03/18 Javascript
Vue入门之animate过渡动画效果
2018/04/08 Javascript
javascript中的数据类型检测方法详解
2019/08/07 Javascript
JS中async/await实现异步调用的方法
2019/08/28 Javascript
Vue 2.0双向绑定原理的实现方法
2019/10/23 Javascript
jquery实现购物车基本功能
2019/10/25 jQuery
解决vue做详情页跳转的时候使用created方法 数据不会更新问题
2020/07/24 Javascript
vue swipeCell滑动单元格(仿微信)的实现示例
2020/09/14 Javascript
多种类型jQuery网页验证码插件代码实例
2021/01/09 jQuery
python获取本地计算机名字的方法
2015/04/29 Python
Python实现可自定义大小的截屏功能
2018/01/20 Python
Python Web框架之Django框架Form组件用法详解
2019/08/16 Python
Python使用selenium + headless chrome获取网页内容的方法示例
2019/10/16 Python
tensorflow 保存模型和取出中间权重例子
2020/01/24 Python
python在CMD界面读取excel所有数据的示例
2020/09/28 Python
BOSE德国官网:尽探索之力,享音乐之极
2016/12/11 全球购物
保卫科工作岗位职责
2014/03/01 职场文书
临床医师个人自我评价
2014/04/06 职场文书
个人委托书范本
2014/09/13 职场文书
2015年幼儿园后勤工作总结
2015/04/25 职场文书
公积金贷款承诺书
2015/04/30 职场文书
缓存替换策略及应用(以Redis、InnoDB为例)
2021/07/25 Redis
MySQL分区路径子分区再分区
2022/04/13 MySQL
MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法
2022/06/14 MySQL