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 相关文章推荐
destoon在各个服务器下设置URL Rewrite(伪静态)的方法
Jun 21 Servers
nginx 设置多个站跨域
Mar 09 Servers
nginx location优先级的深入讲解
Mar 31 Servers
Tomcat执行startup.bat出现闪退的原因及解决办法
Apr 20 Servers
nginx rewrite功能使用场景分析
May 30 Servers
Apache POI操作批量导入MySQL数据库
Jun 21 Servers
Windows server 2022创建创建林、域树、子域的步骤
Jun 25 Servers
win sever 2022如何占用操作主机角色
Jun 25 Servers
Win2008系统搭建DHCP服务器
Jun 25 Servers
vscode远程免密登入Linux服务器的配置方法
Jun 28 Servers
Apache自带的ab压力测试工具的实现
Jul 23 Servers
windows系统搭建WEB服务器详细教程
Aug 05 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
php笔记之:AOP的应用
2013/04/24 PHP
destoon在各个服务器下设置URL Rewrite(伪静态)的方法
2014/06/21 Servers
php 猴子摘桃的算法
2017/06/20 PHP
PHP实现链表的定义与反转功能示例
2018/06/09 PHP
javascript:void(0)的问题使用探讨
2014/04/10 Javascript
使用JS+plupload直接批量上传图片到又拍云
2014/12/01 Javascript
JS逆序遍历实现代码
2014/12/02 Javascript
JS实现鼠标箭头变成一个燃烧烛光效果的方法
2015/02/28 Javascript
jQuery简单实现验证邮箱格式
2015/07/15 Javascript
JavaScript使用encodeURI()和decodeURI()获取字符串值的方法
2015/08/04 Javascript
jQuery实现鼠标悬停背景翻转的黑色导航菜单代码
2015/09/14 Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
2015/12/03 Javascript
基于js对象,操作属性、方法详解
2016/08/11 Javascript
浅谈jquery.form.js的ajaxSubmit和ajaxForm的使用
2016/09/09 Javascript
jQuery中get方法用法分析
2016/12/07 Javascript
JS多文件上传的实例代码
2017/01/11 Javascript
浅谈 vue 中的 watcher
2017/12/04 Javascript
fullpage.js最后一屏滚动方式
2018/02/06 Javascript
axios如何利用promise无痛刷新token的实现方法
2019/08/27 Javascript
[53:15]Newbee vs Pain 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python类继承用法实例分析
2015/05/27 Python
Python win32com 操作Exce的l简单方法(必看)
2017/05/25 Python
磁盘垃圾文件清理器python代码实现
2020/08/24 Python
python下载微信公众号相关文章
2019/02/26 Python
Python自定义函数计算给定日期是该年第几天的方法示例
2019/05/30 Python
python 批量添加的button 使用同一点击事件的方法
2019/07/17 Python
利用Python实现学生信息管理系统的完整实例
2020/12/30 Python
Pytorch - TORCH.NN.INIT 参数初始化的操作
2021/02/27 Python
浅析HTML5中的 History 模式
2017/06/22 HTML / CSS
HTML5 canvas 瀑布流文字效果的示例代码
2018/01/31 HTML / CSS
基督教卡片、励志礼品、家居装饰等:DaySpring
2018/10/12 全球购物
高中毕业自我鉴定
2013/12/22 职场文书
人事任命书范文
2014/06/04 职场文书
2015年小学生新年寄语
2014/12/08 职场文书
新郎答谢词
2015/01/04 职场文书
企业财务管理制度范本
2015/08/04 职场文书