Nginx缓存原理及机制

上篇文章介绍了Nginx一个较为重要的知识点:Nginx实现接口限流。本篇文章将介绍Nginx另一个重要知识点:Nginx缓存原理。其实说到缓存技术大家应该都不会很陌生,缓存技术的基本思想其实是对用户已经访问过的内容在Nginx建立副本,如果在一段时间内(缓存尚未过期)再次访问该数据,则不需要重新发起请求获取数据,可以直接从缓存中读取到该数据,好处在于减少了Nginx与后端服务之间的网络交互,减轻了网络的压力,而且在减少数据传输的延迟时同时可以提升用户访问速度。而且如果碰上后端服务出现异常时,还可以通过缓存进行相应用户请求,提高了后端服务的稳定性。

什么是Nginx缓存?

Nginx基于Proxy Store实现,使用Nginxhttp_proxy模块可以实现类似于squid的缓存功能。当启用缓存时,Nginx会将相应数据保存在磁盘缓存中,只要缓存数据尚未过期,就会使用缓存数据来响应客户端的请求。

如何启用缓存?

Nginx启用缓存需要在最顶层的http节点下配置proxy_cache_path命令。我们先看看proxy_cache_path命令的语法结构:

proxy_cache_path /data/cache keys_zone=niyueling:10m;

可以看到proxy_cache_path命令一共包含两个参数,第一个参数指定缓存保存的本地路径,第二个参数定义缓存数据的共享内存区域的名称和内存区大小。Nginx启动后,缓存加载程序只进行加载一次,加载时会将缓存的元数据加载到共享内存区域,但是如果一次加载整个缓存全部内容可能会使Nginx刚启动的前几分钟性能消耗严重,大幅度降低Nginx的性能。所以可以在proxy_cache_path命令中配置缓存迭代加载。缓存迭代加载一共可以设置三个参数:

loader_threshold - 迭代的持续时间,以毫秒为单位(默认为200)
loader_files     - 在一次迭代期间加载的最大项目数(默认为100)
loader_sleeps    - 迭代之间的延迟(以毫秒为单位)(默认为50)

我们可以看下一个小例子:

proxy_cache_path /data/cache keys_zone=niyueling:10m loader_threshold=300 loader_files=200;

在这个例子中缓存迭代加载可以持续300毫秒或者直到加载满200个项目。在http节点下设置完proxy_cache_path命令,下一步在虚拟服务器配置中配置proxy_cache命令,我们可以看看proxy_cache命令的语法结构:

proxy_cache niyueling;

可以看到proxy_cache命令很简单,就是指定了我们刚才配置的内存区。但是这里有一点需要额外注意的是:我们刚才通过配置proxy_cache_path命令的keys_zone参数配置内存区大小为10m,这并不会限制缓存数据的大小,实际上缓存数据是存储在文件系统中的特定文件的元数据副本。如果想要限制缓存数据的上限,则需要在proxy_cache_path命令中添加max_size参数设置缓存数据上限。说完了proxy_cache命令。

我们接着看看下一个命令:proxy_cache_methods,我们看下该命令语法结构:

proxy_cache_methods[GET HEAD POST];

在虚拟服务器下配置proxy_cache_methods命令可以指定该虚拟服务器下什么类型的HTTP方法可以被缓存。默认情况下GET请求及HEAD请求会被缓存,而POST请求不会被缓存。

接下来看看另外一个常见的命令:proxy_cache_valid,先贴下该命令语法结构:

proxy_cache_valid reply_code [reply_code...] time;

这个命令很有意思,在虚拟服务器下设置该命令,它可以针对不同状态码的响应数据设置不同的缓存时间,我们可以看个简单的小例子:

proxy_cache_valid 200 10m ;
proxy_cache_valid 404 1m ;
proxy_cache_valid 302 5m ;

我们通过上面的命令就可以设置200状态码的缓存时间为10分钟,302重定向的缓存时间为5分钟,404的缓存时间为1分钟。如果想为所有状态码定义相同缓存时间,就可以使用any作为第一个参数:

proxy_cache_valid any 5m;

接下来看看下一个命令:proxy_cache_bypass。一样先看下语法结构:

proxy_cache_bypass  $cookie_nocache  $arg_nocache$arg_comment;

这个命令可以配置不会向客户端响应缓存,而是直接将请求转发给后端服务进行请求数据。可以通过上述命令配置需要绕过缓存的请求URL,也就是说URL中包含该配置的值,则这次请求会直接跳过缓存直接请求后端服务去获取数据。

接下来还有最后一个比较常用的命令:proxy_cache_min_uses。先贴下语法结构:

proxy_cache_min_uses 2;

这个命令可以设置当某请求最少响应几次后会被缓存。若我设置为2则表示每个请求最少被请求2次后会加入到缓存中。

Nginx清除缓存

如果缓存过期则需要从缓存中删除过期的缓存文件,防止新旧缓存出现交错出错,当Nginx接收到自定义HTTP头或者PURGE请求时,缓存将会被清除。

配置缓存清除

我们在HTTP节点下创建一个新变量$purge_method来标识使用PURGE方法的请求并删除匹配的URL

http {
  map $request_method $purge_method {
    PURGE 1;
    default 0;
  }
}

进入虚拟服务器配置,在location中配置高速缓存,并且指定缓存清除请求命令proxy_cache_purge

server {
  listen 80;
  server_name www.niyueling.cn;
  location / {
    proxy_cache niyueling;
    proxy_cache_purge $purge_method;
  }
}

发送清除命令

配置proxy_cache_purge指令后需要发送PURGE请求来清除缓存。例如我们使用PURGE方式请求url:

PURGE www.niyueling.cn/getArticle

getArticle对应的缓存中的数据将被删除。但是,这些高速缓存数据不会从缓存中完全删除,它们将保留在磁盘上,直到它们被删除为非活动状态,或由缓存清除进程处理。

限制IP访问清除命令

清除缓存这种命令一般需要权限才可进行操作,所以我们一般需要配置允许发送缓存清除请求的IP地址:

geo $purge_allowed {
 default 0; 
 49.235.28.88 1; 
 192.168.1.100/24 1; 
}
map $request_method $purge_method {
 PURGE $purge_allowed;
 default 0;
}

Nginx接收到清除缓存请求时,Nginx检查客户端IP地址,若IP地址已经获得清除缓存权限,则$purge_method设置为$purge_allowed,值为1表示允许清除缓存,值为0表示表示IP地址未获得权限。

从缓存中完全删除文件

刚才说过了高速缓存数据不会从缓存中完全删除,它们将保留在磁盘上,直到它们被删除为非活动状态,或由缓存清除进程处理。要完全删除与getArticle相匹配的缓存数据,需要在proxy_cache_path添加参数purger,该参数表示永久的遍历所有缓存条目,并删除与通配符相匹配的条目。

proxy_cache_path /data/cache keys_zone=niyueling:10m purger=on;

字节缓存

当我们请求一个大文件时,因为请求比较耗时,当有下一个请求来临时将不得不等待整个大文件被下载并放入高速缓存。Nginx用缓存片模块填充高速缓存。可以将大文件分为较小的切片,每个范围请求选择将覆盖所请求范围的特定切片,并且如果此范围切片仍未缓存,就将其放入缓存中。启用字节范围缓存需要注意两个条件是否满足:

确保Nginx是使用模块编译的。
使用slice指令指定切片的大小。

可以使用slice命令指定切片大小:

location / {
 slice 1m;
}

使用slice指令指定切片大小时应注意切片大小应适当调整,使切片快速下载。因为切片大小指定太小可能会导致内存使用量过多和大量打开的文件描述符,切片大小指定太大的值可能会导致请求延迟。

接着将$slice_range变量加入到缓存键中:

proxy_cache_key $uri$is_args$args$slice_range;

使用206状态代码缓存响应,缓存有效期30m

proxy_cache_valid 206 30m;

然后设置Range头传递$slice_range变量来将传递范围请求:

proxy_set_header Range $slice_range;

字节缓存小案例:

location / {
 slice 1m;
 proxy_cache niyueling;
 proxy_cache_key $uri$is_args$args$slice_range;
 proxy_set_header Range $slice_range;
 proxy_cache_valid 206 30m;
}

缓存清除小案例

http {
  proxy_cache_path /data/cache keys_zone=niyueling:10m purger=on;
  map $request_method $purge_method {
    PURGE 1;
    default 0;
  }
  
  server {
    listen 80;
    server_name www.niyueling.cn;
    location / {
      proxy_cache niyueling;
      proxy_cache_purge $purge_method;
    }
  }
 
  geo $purge_allowed {
    default 0;
    49.235.28.88 1; 
    192.168.1.100/24 1; 
  }
 
  map $request_method $purge_method {
    PURGE $purge_allowed;
    default 0;
  }
}

本文分享自微信公众号 - 程序猿周先森(zhanyue_org)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏渗透云笔记

MOCTF部分Web题攻略

MOCTF部分Web题解 MOCTF的题目还是比较简单的,今天这篇就当个web类型的入门题吧。本来想把web题解题思路一次全发了,但是篇幅实在是太长了,所以先发...

15720
来自专栏fanzhh的技术笔记

使用pandoc和reveal.js制作html演示文稿

在一个近期的项目中,需要制作一系列演示文稿。我习惯用github管理项目,演示文稿如果使用常见的ppt格式,这个文件只有下载后打开才能看到内容。如果能使用mar...

12110
来自专栏Qt项目实战

Qt编写安防视频监控系统3-通道交换

最开始写通道交换的功能的时候,走了很多弯路,比如最开始用最初级的办法,触发交换的时候,先关闭视频,然后设置新的url重新打开视频,这样处理非常低级而且耗内存还卡...

13230
来自专栏志学Python

走过路过不容错过,Python爬虫面试总结

Selenium 是一个Web 的自动化测试工具,可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。Sel...

13020
来自专栏fanzhh的技术笔记

javascript的“Uncaught SyntaxError: Unexpected token <”问题

使用Django Rest Framework + React 写一个应用,中间需要使用 jquery 读取api服务的json数据,反复出现Uncaught ...

83730
来自专栏数据云团

Django源码学习-19-HttpRequest

Django网络应用开发的5项基础核心技术包括模型(Model)的设计,URL 的设计与配置,View(视图)的编写,Template(模板)的设计和Form(...

5810
来自专栏Web技术研发

PHP系列 | 依赖注入容器和服务定位器

依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。注册会用到一个依赖关系名称和一个依赖关...

13040
来自专栏landv

[php][thinkphp] 记一次Composer Linux版安装以及用它进行thinkphp项目初始化

php中开启exec,system等函数调用系统命令 修改php.ini文件 关掉安全模式 safe_mode = off 然后在看看 禁用函数列表 disab...

11520
来自专栏大史住在大前端

Vue-Router中History模式

history模式是指使用HTML5的historyAPI实现客户端路由的模式,它的典型表现就是去除了hash模式中url路径中的#。对于前端路由基本原理还不了...

11640
来自专栏FreeBuf

CORS-Vulnerable-Lab:与COSR配置错误相关的漏洞代码靶场

此存储库包含与CORS配置错误相关的易受攻击代码。你可以在本地机器上配置易受攻击的代码,以实际利用与CORS相关的错误配置问题。

10920

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励