天下武功唯快不破。随着用户访问请求的压力的剧增,服务器可能处理不过增量太快的请求。单用户请求的响应时间将会变长。如果说,有一个什么方案来解决这个问题,那缓存肯定是首选。
那为何唯独以缓存为佳呢?
因为有了缓存,就不用每次走向原始的数据库里面进行查找。直接现场返回。那就是我们常说的Redis吗?
不是,是 Nginx 的代理缓存,可常用的不是Redis、memcache这些吗?
那如果用户请求在走到接入层就拿到了想要的数据,是不是就不用在访问到后面的Redis缓存啦。从而减少了网络I/O上的开销。
那这在那些场景使用呢? 请听我细细道来
Nginx 代理缓存是什么
缓存代理 指 Nginx 把客户端请求代理到 真实内容源服务器并缓存响应信息到磁盘或内存,如下次访问相同的 URL 请求,就直接从 Nginx 处获取缓存响应。
因 Nginx 做了响应信息的缓存,而 缓存数据是通过代理到真实内容服务器。故称之为 缓存代理
头铁,那什么是代理?代理的方式有哪些呢?
代理就是一个种工作模式,把任务交给别人去完成,你只需等待结果就可以。不用自己全盘接受。
ps:就是第三方的意思
常用代理方式有正、反向代理两大类。
正向代理
客户端发送请求找到代理服务器,由代理服务器向目标服务器发送请求,然后返回响应数据给客户端。整个过程对客户端来说,它是知道目标服务器的真实位置。
比如:你拖朋友从香港代购包包,对于 你 来说,你是知道 朋友具体要去哪里,做什么事情。
场景: 上网。一般都是针对外网IP。对用户透明。
国内 吒吒辉无法直接访问 facebook,但能直接访问到像阿里云在国外部署的云服务器,于是我就可以通过云主机做一个代理,帮助吒吒辉无访问到国外的网站。因为吒吒辉直接访问的云主机在国外,不会被国内网络墙掉。
反向代理
客户端向反向代理服务器发送请求后,反向代理服务器将该请求转发给内部网络上的后端服务器,并将从后端服务器上得到的响应结果返回给客户端。
比如:你直接在海淘相关平台上购买包包。对你 来说,你不知道海淘公司具体要做些什么
场景:Nnginx+PHP。一般针对内网IP,对用户不透明。
对吒吒辉访问 taobao.com场景来看,吒吒辉始终认为访问的是原始服务器,而不是反向代理的服务器。
ps:淘宝使用 Tengine 服务器
但实际上却是反向代理服务器接收了吒吒辉的请求,然后代理到原始服务器取得相关资源后,在返回给吒吒辉
这个是出于安全保护后端资源的措施,只允许代理服务器访问原始资源服务器。 但吒吒辉却不知道。 一般都会后端资源服务器上加上 防火墙,只允许代理服务器来访问
常见的就是:nginx把请求代理到PHP的9000端口,fastcgi_pass 127.0.0.1:9000;
总结:正反向代理是彼此相反,各自互补。
为什么要使用nginx缓存代理
- 减少后端压力,提高网站请求接入,降低请求延时,有利于节省后端服务器的资源。
小吒吒,这个nginx缓存代理和 浏览器 缓存有什么区别,怎么nginx还整出了这个
如果你提了它,那证明你小伙,心还是细。
熟悉的同学可能都知道面对大量用户请求访问的时候,会把一些资源缓存到本地来处理。比如:图片、视频等资源。
但这种这针对于本地静态的化内容,而缓存代理则是针对服务器端的资源,有些比较敏感或者更新比较多的资源就不太适合放到本地,或者资源不是来源于当前服务器,而是来自于上游的其它服务器站点,用缓存代理的方式就可以提升网络的加载速度。
缓存代理应该如何实现?
缓存代理实现还是得根据资源的动态和静态划分,不同的资源类型实现方式不一样,但一般都针对静态,毕竟动态就在于动字,如果后端数据修改了,但是资源却时时未更新上,你说这不是问题?
静态缓存实现
永久缓存配置
配置如下:
server{
listen 80;
server_name localhost
location / {
# 文件保存目录,这里是Windows,如果在Linux需要保证用户执行权限和目录所属用户与nginx启动一致。
# 注: 文件目录需手动创建
root D:zhazhahui/cache;
# 开启本地缓存
proxy_store on;
# 配置缓存用户和组的读写权限
proxy_store_access user:rw group:rw all:r;
# 反向代理时接收的数据临时存储文件的目录,nginx启动后会自动创建生成
proxy_temp_path cache_tmp;
## 利用正则表达式匹配缓存目录中的文件、目录或符号链接是否存在
# !-e 检查一个文件、目录或符号链接是否存在,不存在就执行 ()中的指令
# $request_filename为nginx内置变量,为当前请求的URI,就是你域名站点后面出现的文件路径
if(!-e $request_filename) {
proxy_pass http://zhazhahui.com:8080;
}
}
临时缓存设置
Nginx的临时缓存,是使用 proxy_cache
指令设置的临时缓存配置,它采用md5算法将请求URL地址进行哈希(hash)计算后,根据配置文件中指定缓存目录,来保存响应后的数据。
那这永久缓存和临时缓存有啥区别?我该如何选择呢? 放心,我都懂,后面细聊,超乎你象限!
- 缓存配置
在
`
nginx.conf 中的 http模块
`
添加如下 配置。
#代理临时目录
proxy_temp_path /usr/local/nginx/proxy;
#Web缓存目录和参数设置
proxy_cache_path /usr/1ocal/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:50m inactive=1m max_size=500m;
/usr/local/nginx/proxy_cache_dir 参数:表示用户自定义的缓存文件保存目录。
- levels参数:表示缓存目录下的层级目录结构,它是根据哈希后的请求URL地址创建的,目录名称从哈希后的字符串结尾处开始截取。
假设哈希后的请求链接地址为 af7098a15e430326197ee01516fdace0, 则levels=1:2表示,第1层子目录的名称是长度为1的字符0,第2层子目录的名称是长度为2的字符ce。
- keys_zone参数: 指定缓存区名称及大小,例如:cache_one:50m表示缓存区名称为 cache_one,在内存中的空间是50MB。
- inactive参数:表示主动清空在指定时间内未被访问的缓存。例如:1m 清空在1分钟内未被访问过的缓存,1h表示1小时,1d表示1天等。
- max_size参数:表示指定磁盘空间大小。例如,500m、10g。需要注意的是,Nginx在进行缓存时, 首先会被写人 proxy_temp_path 指定的临时目录中,因此建议proxy_cache_path 和proxy_temp_path 指令设置的目录应在同一个文件系统中,避免不同文件系统之间的磁盘I/O消耗。
为啥缓存存储要设置一个临时目录和真实的数据存储呢?
- 在Server块添加临时缓存配置
listen 80;
server name zhazha.hui.test;
#增加两个响应头信息,用于获知访问的服务器地址与缓存是否成功
add_header X-Via $server addr;
add_header X-Cache $upstream cache status;
location /{
#设置缓存区城名称
proxy_cache cache_one;
#以域名、URI、参数组合成Web缓存的Key值,Nginx根据Key值哈希
proxy_cache_key $host$uri$is_args$args;
#对不同的HTTP状态码设置不同的缓存时间
proxy_cache valid 200 10m;
#200缓存10分钟
proxy_cache_valid 304 1m;
#304缓存1分钟
proxy_cache_valid 301 302 1h;
# 301、302缓存1小时
proxy_cache_valid any 1m;
#其他未设置的状态码缓存1分钟
#设置反向代理
proxy_pass http://192.168.78.128;
- $host:服务器的域名,如zhazha.hui.test
- $uri:域名和参数之间的部分,如/index.html。
- $is_args: 有URL参数时,则值为?,否则为空字符串。
- $args:保存URL参数,如a=1&b=2,没有参数时为空字符串。
- 利用$is_args和$args,可以实现根据不同URL参数缓存不同文件。
为了便于在浏览器端查看是否正确缓存,可配置 add_header 指令添加了
两个响应消息头。其中X-Via表示服务器地址,利用内置变量$server_addr 获取,另一个X-Cache表示资源缓存状态,利用内置变量$upstream_cache_status 获取。$upstream_cache_status 的返回值有7个,如下所示:
| 返回值 | 说明 |
| :----: | :----: |
| HIT| 未命中,请求被传送到后端 |
| MISS | 未命中,请求被传送到后端 |
| EXPIRED | 缓存已经过期,请求被传送到后端 |
| UPDATING | 正在更新缓存,将使用旧的应答 |
| STALE | 无法从后端服务器更新缓存时,返回了旧的缓存内容(可通过proxy_ cache_ use_stale指令配置) |
| BYPASS | 缓存被绕过了(可通过proxy_cache_bypass指令配置) |
| REV ALIDA TED |启用proxy_ cache_ revalidate 指令后,当缓存内容过期时,Nginx通过一次If-Modified- Since的请求头去验证缓存内容是否过期,此时会返回该状态 |
Ps: 那这永久缓存和临时缓存有啥区别呢?
永久和临时在使用看,配置就不一样,临时是针对 HTTP 作用域,所以整个HTTP下配置的 Server 站点都可以享受,基本适合一切的缓存代理来做,并且它不会一直存在。失效就不用了。
而永久就不一样,它只是针对单个Server来说,符合那种单点业务,比如流量高访问的高的页面,用它直接缓存本地后面即可直接使用。缓存代理解析过程是如何实现的?
HTTP 请求匹配到server站点后,就直接找到相关 location 规则,然后再向后端源服务器请求数据,得到响应结果并缓存起来。 这里就是核心, 缓存代理需先生产缓存后才能去命中缓存,如果都没有那只有去后端源服务里面获取。
缓存为啥要用哈希算法生成缓存目录呢?
因为哈希。它的时间复杂度是O(1)。
如不使用哈希,那每次请求到后端进行缓存检索时,就需从众多的缓存中挨个进行对比,这样查找匹配的效率就变得很低。如果用来哈希算法,每次缓存命中时直接根据请求计算出哈希码,然后再哈希表下面进行对比,这样在众多的缓存内容下检索救护更快速。
那算法的本质是什么?
哎呦,小伙还喜欢问这个。 很多人都感觉算法很难懂,首先你得从大观上来看。这里还得提下 数据结构和算法
算法实质就是解决问题的方案,是一系列解决问题的清晰指令,而数学思想是优化这种方案的武器。
其实不用算法,也会有很多种方式来解决问题,但有了算法它的效率会更快,就好像你做 从1-1000相加的结果
普通方式:从 1+2+3+.....+1000。 这属于毫不讲理型,
算法方式:(1+1000)x(1000/2) 这属于大脑开动型
算法说白了就是用算术解决问题的方法,用一些数学上面的方式去解决特定问题的方案。
而数据结构就是存储数据的一种形式,数据结构本身在访问和处理上的效率就会高于普通的形式,因为它们会按照指定的结构去存储和读取。 所以一般在编写程序都会考虑时间和空间复杂度。 故常会结合这两种东西来解决实际资源消耗大的问题
FastCGI缓存
FastCGI模块主要能够接受PHP-FPM请求响应,而且能够与任何兼容FastCGI协议的服务器通信。而FastCGI缓存只是该模块下的一部分,属于动态资源请求。
而前面临时+永久缓存都针对整个网络请求,并不是FastCGI请求部分,如果有了它,那么将大大减少nginx和PHP的网络通信。
常用指令
fastcgi_cache
- 语法:fastcgi_cache zone_name
- 说明:用于设置哪个缓存区将被使用,zone_name 的值为 fastcgi_cache_path 指令创建的缓存区名称
- 作用域:http、server、location 默认值: off
fastcgi_cache_path
- 语法:fastcgi_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];
- 说明:用于设置哪个缓存区将被使用,zone_name 的值为 fastcgi_cache_path 指令创建的缓存区名称。
- 作用域:http
例如:fastcgi_cache_path /usr/local/nginx/fastcgi_cache_dir levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=30g ;
- levels 指定该缓存空间有两层hash目录,第一层目录为1个字母,第二层为2个字母,保存的文件名会类似 /usr/local/nginx/fastcgi_cache_dir/c/29/XXXX;
- keys_zone 参数用来为这个缓存区起名;
- 500m 指内存缓存空间大小为500MB;
- inactive 的1d 指如果缓存数据在1天内没有被访问,将被删除;
- max_size 的30g 是指硬盘缓存空间为30GB
fastcgi_cache_methods
- 语法: fastcgi_cache_methods [GET HEAD POST] ;
- 说明:该指令用于设置缓存哪些HTTP方法,默认缓存HTTP GET/HEAD 方法,不缓存HTTP POST方法
fastcgi_cache_min_uses
- 语法: fastcgi_cache_min_uses the_number;
- 说明:该指令用于设置缓存的最小使用次数,默认值为1.
fastcgi_cache_valid
- 语法: fastcgi_cache_valid reply_code [reply_code...] time;
- 说明: 该指令用于对不同返回状态码的URL设置不同的缓存时间.
- fastcgi_cache_valid 200 302 10m ;
fastcgi_cache_valid 404 1m ;
- 设置200,302状态的URL缓存10分钟,404状态的URL缓存1分钟.如果不指定状态码,直接指定缓存时间,则只有200,301,302状态的URL缓存5分钟.
fastcgi_cache_key
- 语法:fastcgi_cache_key line ;
- 该指令用来设置Web缓存的Key值,Nginx根据Key值md5哈希存储缓存.一般根据FastCGI服务器的地址和端口,$request_uri(请求的路径)等变量组合成fastcgi_cache_key。
配置FastCGI缓存
1、编辑nginx.conf
http{
#fastcgi_temp_path和fastcgi_cache_path指定的路径必须在同一分区
fastcgi_temp_path /usr/local/nginx/fastcgi_temp_path ;
#设置Web缓存区名称为cache_one,内存缓存空间大小为500MB,自动清除超过1天没有被
#访问的缓存数据,硬盘缓存空间大小为30G
fastcgi_cache_path /usr/local/nginx/fastcgi_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=30g ;
}
2、修改站点配置文件中的fastcgi内容
server{
location ~ .*\.(php|php5)$ {
#使用Web缓存区cache_one
fastcgi_cache cache_one ;
#对不同的HTTP状态码缓存设置不同的缓存时间
fastcgi_cache_valid 200 10m ;
fastcgi_cache_valid 301 302 1h ;
fastcgi_cache_valid an 1m ;
#设置Web缓存的key值,Nginx根据key值md5哈希存储缓存,这里根据"FastCGI服务
# "FastCGI器的IP+端口+求的URI" 组合成Key。
fastcgi_cache_key 127.0.0.1:9000$requet_uri ;
#FastCGI服务器
fastcgi_pass 127.0.0.1:9000 ;
fastcgi_index index.php ;
include fcgi.conf ;
}
}
缓存清理配置
Nginx缓存虽减轻了后端服务器的压力,但是会导致文件修改后无法及时更新缓存,只有及时删除服务器中的缓存文件,Nginx才会重新请求后端服务器。
目前,Nginx 官方不支持清理指定URL的缓存,需借助第三方(ngx_cache_purge)模块才可以实现。
1.备份已安装的Nginx
在添加ngx_cache_purge 模块前,关闭Nginx服务,备份已有的Nginx目录。
[root@吒吒辉]# cp -r /usr/local/nginx /usr/1ocal/nginx_old2
2.重新编译安装Nginx
在GitHub平台可以获取ngx_cache_purge模块的源代码,参考下载地址为
https://github.com/FRiCKLE/ngx_cache_purge/tags
这里选择zip格式的文件。
下载完成后将其上传到root目录下,解压并重命名为ngx_cache_purge,具体命令
[root@ localhost ~ ]# unzip ngx_cache_purge-2.3.zip
[root@ localhost ~]# mv ngx_cache_purge-2.3 /usr/1ocal/ngx_cache_purge
接着,进人 Nginx 文件的解压目录,在./configure时添加对nginx-cachepurge模块的支持,完成Nginx编译选项的配置,具体命令如下。
[root@ localhost ~]# cd nginx-1.10.1
[roote localhost nginx-1.10.1]# ./configure \
# 指定nginx安装目录
--prefix= /usr/local/nginx \
--add-module= /usr/local/ngx_cache_purge \
# 启用https支持。
--with-http_ss1_module
[roote localhost ~]# make && make install
完成Nginx的编译和安装后,启动Nginx服务,在浏览器中访问测试。如果看到Nginx 的默认欢迎页面表示安装成功。 或者使用 nginx -V命令查看是否按照成功模块
3.配置缓存清理功能
安装完 ngx_cache_purge 模块后,可使用该模块提供的 proxy_cache_purge 指令实现缓存清理。在使用 proxy_cache_purge指令时需要遵循如下规则。
- 指定的缓存区名称要与 proxy_cache_path 指令中出现的缓存区名称一致。
- 指定的Key值组成规则,要与 proxy_cache_key 指令设置的规则相同。
- 清理缓存的location编写位置,要在server块中所有location之前,防止其他正则location提前匹配。
根据前文设置得临时缓存配置,修改Nginx的配置文件nginx.conf,在server块中添加以下用于清理缓存的配置。
1 location ~ /purge(/.* ){
2 allow 192.168.78.1;
3 deny all;
4 proxy_cache_purge cache_one Shost$1$is_args$args;
5 }
- 第1行,用于以正则方式匹配用户的请求,请求地址符合/purge/URI形式时,就会清理URI对应的缓存文件。
- 第2-3行用于指定允许清理缓存的客户端,此处表示仅允许IP地址为 192.168.78.1的客户端清理缓存。
- 第4行通过proxy_cache_purge 指令,指定名称为 cache_one 的缓存区,和待清理缓存文件的Key值组成规则。其中,$1表示location正则表达式中的子模式 "(/.*)" 的匹配结果,对应生成缓存Key时的$uri
4.访问测试
在内容源服务器的网站根目录中,编写测试文件test.html,具体内容如下。
吒吒辉欢迎你!
吒吒辉欢迎你一起入群交流学习
< /body>
然后,在浏览器中访问 curl zhazha.hui.test/test.html(这里是采用本地的云服务器访问,你可自行更换为外网IP)
此时可以看到哈希后生成的缓存文件名称及目录结构。采用tree 命令查看文件目录树,
注: 安装 yum -y install tree
最后,在浏览器中访问 test.ng.test/ purge/test.html,清理test.html的缓存文件,如下所示。从图中可以看到当前清理的缓存文件的key值,以及存放缓存文件的路径。
为了验证是否成功清理了缓存文件,在缓存服务器中查看缓存目录,已经没有文件
总结:
- 缓存代理分为动静两大类,通过它可以减少下游服务网络IO的开销、程序处理时间的消耗等好处。
- 缓存方式为永久、临时缓存2大类,一般使用临时缓存
- 缓存有失效时间,如果数据需要及时更新,那需删除原来数据
我命由我不由天
如有帮助,欢迎关注、分享。帮帮在互联网浪潮中不断挣扎的男子,微信搜索【莲花童子哪吒】 获取体系化内容,还加我纳入群聊,一起交流学习进步提升。