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解决403 forbidden的完整步骤
Apr 01 Servers
Nginx配置https的实现
Nov 27 Servers
nginx负载功能+nfs服务器功能解析
Feb 28 Servers
nginx实现多geoserver服务的负载均衡
May 15 Servers
利用Apache Common将java对象池化的问题
Jun 16 Servers
Zabbix对Kafka topic积压数据监控的问题(bug优化)
Jul 07 Servers
本地搭建minio文件服务器(使用bat脚本启动)的方法
Jul 15 Servers
windows server2016安装oracle 11g的图文教程
Jul 15 Servers
彻底卸载VMware虚拟机的超详细步骤记录
Jul 15 Servers
Tomcat安装使用及部署Web项目的3种方法汇总
Aug 14 Servers
ubuntu开机后ROS程序自启动问题
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
免费手机号码归属地API查询接口和PHP使用实例分享
2014/04/10 PHP
PHP登录(ajax提交数据和后台校验)实例分享
2016/12/29 PHP
Laravel5.5新特性之友好报错以及展示详解
2017/08/13 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
javascript 弹出层组件(升级版)
2011/05/12 Javascript
Kibo 用于处理键盘事件的Javascript工具库
2011/10/28 Javascript
Jquery chosen动态设置值实例介绍
2013/08/08 Javascript
JS复制到剪贴板示例代码
2013/10/30 Javascript
ExtJS4中的requires使用方法示例介绍
2013/12/03 Javascript
javascript实现节点(div)名称编辑
2014/12/17 Javascript
js实现select二级联动下拉菜单
2020/04/17 Javascript
炫酷的js手风琴效果
2016/10/13 Javascript
jquery插件锦集【推荐】
2016/12/16 Javascript
JavaScript监听手机物理返回键的两种解决方法
2017/08/14 Javascript
Vue工程模板文件 webpack打包配置方法
2017/12/26 Javascript
9102年webpack4搭建vue项目的方法步骤
2019/02/20 Javascript
JavaScript this在函数中的指向及实例详解
2019/10/14 Javascript
使用Vue实现调用接口加载页面初始数据
2019/10/28 Javascript
JS立即执行的匿名函数用法分析
2019/11/04 Javascript
JavaScript对象访问器Getter及Setter原理解析
2020/12/08 Javascript
原生js实现放大镜组件
2021/01/22 Javascript
[01:03:03]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
Python 深入理解yield
2008/09/06 Python
Python实现简单截取中文字符串的方法
2015/06/15 Python
python机器学习库常用汇总
2017/11/15 Python
对python opencv 添加文字 cv2.putText 的各参数介绍
2018/12/05 Python
CSS3实现头像旋转效果
2017/03/13 HTML / CSS
法国综合购物网站:RueDuCommerce
2016/09/12 全球购物
adidas菲律宾官网:adidas PH
2020/02/07 全球购物
购房委托书范本
2014/09/18 职场文书
2015年秘书个人工作总结
2015/04/25 职场文书
2015最新婚礼司仪主持词
2015/06/30 职场文书
2016新年感言
2015/08/03 职场文书
2016年第十四个公民道德宣传日活动总
2016/04/01 职场文书
探究Mysql模糊查询是否区分大小写
2021/06/11 MySQL
Python制作表白爱心合集
2022/01/22 Python