因为一些场景,需要对某些请求进行优化,这里选择直接对http服务做nginx静态缓存

设置缓存

在http中设置缓存目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
windows配置
proxy_temp_path D:\\nginx\\proxy_temp;
proxy_cache_path D:\\nginx\\proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1h max_size=1g;

linux配置
proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=1h max_size=1g;


proxy_cache_path /www/ levels=1:2 keys_zone=Z:10m inactive=1m max_size=30g;
这一句定义一个区域,名字是 Z ,在内存中的空间为10MB ,硬盘中的最大空间为 30G;
inactive=1m 如果缓存1分钟没人访问,nginx 会删除掉这些缓存


levels参数负责设置缓存目录级别。假设cache主目录为/data/nginx/cache。
#如果没有特殊指明此参数值,则默认是放在cache主目录下
/data/nginx/cache/d7b6e5978e3f042f52e875005925e51b

#当levels=1:2时,表示是两级目录,1和2表示用1位和2位16进制来命名目录名称。在此例中,第一级目录用1位16进制命名,如b;第二级目录用2位16进制命名,如2b。所以此例中一级目录有16个,二级目录有16*16=256个
/data/nginx/cache/b/2b/d7b6e5978e3f042f52e875005925e51b
总目录数为16*256=4096个。

#当levels=1:1:1时,表示是三级目录,且每级目录数均为16个
/data/nginx/cache/b/c/d/d7b6e5978e3f042f52e87500592
总目录数为16*16*16=4096个。

#当levels=2:2:2时,表示是三级目录,且每级目录数均为16*16个
/data/nginx/cache/2b/3c/4d/d7b6e5978e3f042f52e875005925e51b
总目录数为256*256*256个。
 
#当levels=2时,表示是一级目录,且目录数为16*16=256

proxy_cache相关指令说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1.proxy_cache指令
语法:proxy_cache zone_name;
默认值:none
使用配置段:http,server,location
该指令用于设置哪个缓存区将被使用,zone_name的值为proxy_cache_path指令创建的缓存区名称


2.proxy_cache_path指令
语法:proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];
默认值:none
使用配置段:http
该指令用于设置缓存文件的存放路径
proxy_cache_path /usr/local/nginx-1.6/proxy_cache levels=1:2 keys_zone=cache_one:100m inactive=2d max_size=2g;
levels指定该缓存空间有两层hash目录,第一层目录为1个字母,第二层为2个字母
keys_zone参数设置这个缓存区的名称和内存缓存空间大小
inactive参数设置数据多长时间没有被访问将删除
max_size参数设置硬盘缓存空间大小


3.proxy_cache_methods指令
语法:proxy_cache_methods [GET HEAD POST];
默认值:proxy_cache_methods GET HEAD POST;
使用配置段:http,server,location
该指令用于设置缓存哪些HTTP方法



4.proxy_cache_min_uses指令
语法:proxy_cache_min_uses number;
默认值:proxy_cache_min_uses 1;
使用配置段:http,server,location
该指令用于设置缓存的最小使用次数



5.proxy_cache_valid指令
语法:proxy_cache_valid
默认值:none
使用配置段:http,server,location
该指令用于对不同返回状态码的URL设置不同的缓存时间
例如,设置200、302状态的URL缓存10分钟,404状态的URL缓存1分钟,不指定状态码表示200、301、302
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid 5m;
proxy_cache_valid any 1m; 其余没有定义的状态码,


6.proxy_cache_key指令
语法:proxy_cache_key line;
默认值:none
使用配置段:http,server,location
该指令用来设置web缓存的key值,nginx根据key值MD5哈希存储缓存,根据域名、请求路径等变量
proxy_cache_key $host$uri$is_args$args;

缓存文件名称和路径计算方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
先看下proxy_cache_path的常见配置:
proxy_cache_path /usr/local/nginx/cache levels=1:2 keys_zone=one:10m max_size=1g;


在上面这行配置中定义了一个反向代理缓存路径:
1) nginx反向代理缓存的目录为/usr/local/nginx/cache;
2) 缓存文件的key和其它信息放在一个10M的共享内存中,命名为one;
3) 缓存文件最大占用1G磁盘空间;

那还有一个level=1:2是什么意思呢?举个例子吧:
比如有一个URL是https://www.baidu.com/1.png,那么这个图片如果被缓存那他的路径就是
/usr/local/nginx/cache/3/7e/fd2e5e1717059b0504614c7d6d8367e3



计算方法:
1) nginx先把请求地址/1.png用md5进行哈希(计算时使用缓存的key进行hash,key参考上一个指令),得到fd2e5e1717059b0504614c7d6d8367e3
2) level=1:2就是把最后一位数3拿出来建一个目录,然后再把3前面的2位建一个目录,最后把刚才得到的这个缓存文件放到3/7e目录中。

同样的方法推理,如果配置level=1:1,那么缓存文件的路径就是/usr/local/nginx/cache/9/d/e0bd86606797639426a92306b1b98ad9

上面的例子只是最简单的URL,如果带参数呢?
比如https://www.baidu.com/1.png?v=1,那么缓存路径还是一样吗?

先对比下这个两个配置:
proxy_cache_key $uri;
proxy_cache_key $uri$is_args$args;

第一个配置只根据不带参的$uri进行哈希,所以这时候加了参数和没加参数是一样的结果;
第二个配置就是把域名之后所有的内容(也就是$request_uri)都进行哈希。



说明:
1) MD5哈希过之后的路径是十六进制的,对于nignx来说查询速度更快;
2) level=1:2会比level=1:1建立更多的目录,适合缓存海量文件,因为单个目录下的文件太多会降低IO性能;
3) 缓存会先被写入写入临时文件,所以建议proxy_cache_path和proxy_temp_path放在同一个文件系统当中,避免不通文件系统之间的磁盘IO消耗;
4) nginx有通过HTTP协议删除缓存的第三方插件,是否使用,看自己需求



java测试代码
import org.apache.shiro.crypto.hash.SimpleHash;
SimpleHash simpleHash = new SimpleHash("MD5", "https://www.baidu.com/1.png");
String s = simpleHash.toHex();
System.out.println(s);

在server上设置规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
location =/ {
# 选择缓存名称
proxy_cache cache_one;
# 缓存的请求方法
proxy_cache_methods GET HEAD POST;
# 参考proxy_cache指令说明
proxy_cache_min_uses 1;
# 200请求结果和302请求结果的缓存时间
proxy_cache_valid 200 302 5m;
# 404请求结果的缓存时间
proxy_cache_valid 404 1m;
# 其他请求结果的缓存时间
proxy_cache_valid any 1m;
# 缓存的key,内部使用的变量参考下文中的内置全局变量
# 这里要注意,不同的server如果key一样,就会使用同一个缓存结果
proxy_cache_key "$host:$server_name$uri$is_args$args";

# 反向代理到 8080 端口
proxy_pass http://localhost:28002;
# 多层反向代理的时候,识别域名的头
proxy_set_header Host $host;
# 跨域请求头
add_header Access-Control-Allow-Origin *;
}

设置静态资源的缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
通过nginx对服务器上的静态资源进行过期时间设置和对资源进行压缩传输来减少服务器的带宽开销。
这里是对ico,gif,bmp,jpg,jpeg,swf,js,css,mp3文件进行本地缓存

http标签下设置压缩比例
对文本、js和css文件进行压缩,一般情况下,压缩后的大小是原始大小的25%,甚至更小。
gzip on;
gzip_min_length 1000;
gzip_buffers 4 8k;
gzip_types text/plain application/x-javascript text/css;


缓存目录设置(参考上面一级设置缓存目录)


在server中设置静态资源的缓存时间(30天)和目标资源的访问路径
location ~* .(ico|gif|bmp|jpg|jpeg|png|swf|js|css|mp3) {
root /usr/share/nginx;
expires 30d;
}

location语法

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
location [=|~|~*|^~] /uri/ { … }

= 开头表示精确匹配

^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。

~ 开头表示区分大小写的正则匹配

~* 开头表示不区分大小写的正则匹配

!~和!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则

/ 通用匹配,任何请求都会匹配到。

说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1、精准匹配和一般匹配
请求URL:http://192.168.60.106/zg/  访问时匹配的是:=/zg/
 
2、精准匹配和一般匹配,uri后面不带“/”匹配
请求URL:http://192.168.60.106/zg/  访问时匹配的是:/zg
 
3、精准匹配和一般匹配,uri前面和后面都不带“/”
请求URL:http://192.168.60.106/zg/ 访问时匹配的是:= zg

4、精准匹配和一般匹配,uri带"/"和不带"/"匹配
请求URL:http://192.168.60.106/zg/ 访问时匹配的是:/zg/ 顺序换也是一样
综上所述:路径相同时的精准匹配优先,必须是满足/uri/或者uri,要么uri两边都加/,要么uri两边都不加斜杆的情况

5、一般匹配时的匹配规则
在html下创建file,lfile文件夹,然后在file下创建images文件夹,在images下创建aa文件夹,在lfile下创建images文件夹,接着在images下创建aa文件夹,然后同时在两个aa文件夹下导入test.jpg图片,这样file和lfile下都有images/aa路径
请求url:http://192.168.60.106/images/aa/test.jpg,既能匹配/images/,又能匹配/images/aa,这时以最长uri匹配优先,匹配的是:/images/aa

6、^~开头的非正则匹配和一般匹配
^~代表非正则匹配,非正则,不需要继续正则匹配。
^~:如果这个匹配使用^〜前缀,搜索停止。这个前缀官网和网上都说得很含糊,加上这个前缀,是会停止搜索正则匹配,但是对一般匹配是不会停止的,也就是说还是可以匹配到一般匹配的。
请求url: http://192.168.60.106/images/aa/test.jpg,匹配结果:/images/aa/

 
7、^~开头的非正则匹配和正则匹配
~ 开头表示区分大小写的正则匹配
请求url: http://192.168.60.106/images/aa/test.jpg,匹配结果:^~/images/


8、严格精准匹配和正则匹配
严格精准匹配,如果被严格精准匹配到了,则不会继续搜索正则匹配
如果http://192.168.60.106,这个就严格精准匹配到了 /,则不会继续匹配 ~ \.html$
如果:http://192.168.60.106/index.html,则会被/ 匹配到,但是不是严格精准匹配,则会继续搜索正则匹配
 
9、正则匹配规则
都是正则uri的情况下,匹配是按照编辑顺序的
请求URL:http://192.168.60.106/prefix/index.html,会优先匹配前面定义的location。

10、@开头的uri
@开头的,如果请求的 URI 存在,则本 nginx 返回对应的页面;如果不存在,则把请求代理到baidu.com 上去做个弥补,其实就是做了一个容错,把找不到的url全部转发到fallback的反向代理服务器去。
 
最后总结:
1. 先判断精准命中,如果命中,立即返回结果并结束解析过程
2. 判断普通命中,如果有多个命中,记录下来最长的命中结果
3、如果是^~开头的命中,则不会继续搜索正则命中,但是会继续搜索一般命中
4. 继续判断正则表达式的解析结果,按配置里的正则表达式顺序为准,由上到下开始匹配,一旦匹配成功立刻返回结果,并结束解析过程。

延伸分析:a. 普通命中:顺序无所谓,是因为按命中长短来确定的   b. 正则命中:顺序有所谓,因为是从前往后命中的

nginx常用内置变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
nginx的配置文件中可以使用的内置变量以美元符$开始,也有人叫全局变量。其中,部分预定义的变量的值是可以改变的。

$arg_PARAMETER 这个变量值为:GET请求中变量名PARAMETER参数的值。

$args 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改

$binary_remote_addr 二进制码形式的客户端地址。

$body_bytes_sent 传送页面的字节数


$content_length 请求头中的Content-length字段。

$content_type 请求头中的Content-Type字段。

$cookie_COOKIE cookie COOKIE的值。

$document_root 当前请求在root指令中指定的值。

$document_uri 与$uri相同。

$host 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。

$hostname 机器名使用 gethostname系统调用的值

$http_HEADER HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值), $http_referer...;

$sent_http_HEADER HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type...;

$is_args 如果$args设置,值为"?",否则为""。

$limit_rate 这个变量可以限制连接速率。

$nginx_version 当前运行的nginx版本号。

$query_string 与$args相同。

$remote_addr 客户端的IP地址。

$remote_port 客户端的端口。

$remote_user 已经经过Auth Basic Module验证的用户名。

$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。

$request_body 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。

$request_body_file 客户端请求主体信息的临时文件名。

$request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。

$request_method 这个变量是客户端请求的动作,通常为GET或POST。
包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。

$request_uri 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。

$scheme 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;

$server_addr 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。

$server_name 服务器名称。

$server_port 请求到达服务器的端口号。

$server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。

$uri 请求中的当前URI(不带请求参数,参数位于$args),不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html

删除缓存

1
2
3
1. 安装第三方模块(Nginx cache purge 模块),配置删除url缓存

2. 自己计算出url缓存文件,然后自己写程序手动缓存文件(适配性更好,推荐)。相关计算规则参考上文。

参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
缓存配置
https://www.jb51.net/article/69217.htm

nginx的proxy_cache缓存相关配置
https://blog.51cto.com/hnr520/1686896

计算路径参考
https://blog.51cto.com/netexr/1252242

匹配规则
https://blog.csdn.net/luoyang_java/article/details/83507193

其他
https://www.nginx.cn/