第02章-场景实践篇
# 2.1 静态资源web服务
# 2.1.1 静态资源服务场景-CDN
Nginx资源存储中心会把静态资源分发给“北京Nginx”,“湖南Nginx”,“山东Nginx”。
然后北京User发送静态资源请求,通过CDN,找到离自己最近的“北京Nginx”。
# 2.1.2 配置语法
# 文件读取
Syntax: sendfile on | off;
Default: sendfile off;
Context: http, server, location, if in location
2
3
引:—with-file-aio 异步文件读取
# tcp_nopush
作用:sendfile开启的情况下,提高网络包的传输效率
把多个包整合,一次性发送,大文件传输推荐打开
Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http, server, location
2
3
# tcp_nodelay
作用:keepalive连接下,提高网络包的传输实时性
Syntax: tcp_nodelay on | off;
Default: tcp_nodelay on;
Context: http, server, location
2
3
# 压缩
(1) 压缩开关
作用:传输压缩
Syntax: gzip on | off;
Default: gzip off;
Context: http, server, location, if in location
2
3
(2) 压缩比
Syntax: gzip_comp_level level;
Default: gzip_comp_level 1;
Context: http, server, location
2
3
压缩比越高传输的数据包越小,但是压缩本身也会消耗服务端性能,需综合考虑
(3) 压缩内容
除了“text/html”之外,还为指定的MIME类型响应进行压缩。通配符“*”匹配任何MIME类型。“text/html”类型的响应总是被压缩的。
Syntax: gzip_types mime-type ...;
Default: gzip_types text/html;
Context: http, server, location
2
3
(4) 压缩需要的版本
设置压缩响应所需的请求的最低HTTP版本
Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
Context: http, server, location
2
3
(5) 预读压缩
优先响应原本已有的压缩文件,而不是压缩后再返回。
例如,请求指定路径的 index.html,先检查该路径下是否存在 index.html.gz,如果存在直接响应该压缩文件,而不进行压缩了。节约了压缩时间,提高效率。
Syntax: gzip_static on | off | always;
Default: gzip_static off;
Context: http, server, location
2
3
扩展Nginx压缩模块
- http_gzip_static_module:预读gzip功能
- http_gunzip_module:应用支持gunzip的压缩方式
# 2.1.3 Nginx用于浏览器缓存
# 浏览器缓存机制
浏览器缓存是基于HTTP协议定义的缓存机制(如:Expires;Cache-control等)
浏览器无缓冲场景:
浏览器有缓存场景:
缓存过期校验机制:
校验点 | 依赖的Header |
---|---|
校验是否过期 | Expires、Cache-Control(max-age) |
协议中Etag头信息校验 | Etag |
Last-Modified头信息校验 | Last-Modified |
缓存过期校验步骤:
本地客户端通过Expires、Cache-Control(max-age)字段校验本地缓存是否过期。
通过Etag头信息校验服务器缓存是否过期,如果不过期,不走第三步,否则执行下一步。
通过Last-Modified头信息校验服务器缓存是否过期,如果不过期,直接返回,否则请求服务端。
- Expires出现在Http1.0版本;Cache-Control(max-age)出现在Http1.1版本;
- Etag的值是一串字符串,在一秒时间内更新的话,服务端是无法识别的,这个时候就需要Etag校验
- Last-Modified的值是具体时间:年-月-日 时:分:秒。Last-Modified用来跟服务端的缓存文件进行校验,如果服务端缓存文件在新的时间有新的更新,客户端请求的时间就会跟服务端缓存文件时间对比,这个时候就会出现客户端请求的时间跟服务端请求的时间不一致。 这样的话,服务端就会把最新的文件返回给客户端,这个利用的就是请求头中的Last-Modified头信息进行校验的。
# Nginx配置缓存
Nginx使用expires配置,在响应头中添加:Cache-Control、Expires头信息,实现缓存
Syntax: expires [modified] time;
expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location
2
3
4
开启expires
#设置缓存时间为30s
location ~ \.(html,htm)$ {
expires 30s;
root /opt/app/html;
}
2
3
4
5
第一次请求:
###################### 请求头 ######################
#服务器设置缓存时间为30s
Cache-Control: max-age=30
#最后修改时间,之后的请求都会放在If-Modified-Since里带上
Last-Modified: Thu, 31 Dec 2020 03:24:48 GMT
#之后的请求都会放在If-None-Match里带上
ETag: "5fed4480-1e"
#缓存过期时间,每次都是 本次响应时间点+设置的过期时间
Expires: Thu, 31 Dec 2020 05:19:19 GMT
2
3
4
5
6
7
8
9
第二次请求:
###################### 请求头 ######################
#这个0是由浏览器加的,浏览器控制每次都让服务器做过期校验,决定返回的响应状态码
Cache-Control: max-age=0
#第二次请求开始带上,校验Etag是否过期
If-None-Match: "5fed4480-1e"
#第二次请求开始带上,校验资源是否更改
If-Modified-Since: Thu, 31 Dec 2020 03:24:48 GMT
###################### 响应码 ######################
304 Not Modified
###################### 响应头 ######################
Cache-Control: max-age=30
ETag: "5fed4480-1e"
Expires: Thu, 31 Dec 2020 05:24:46 GMT
2
3
4
5
6
7
8
9
10
11
12
13
14
未开启expires
第一次请求:
###################### 响应头 ######################
ETag: "5fed6c59-a"
Last-Modified: Thu, 31 Dec 2020 06:14:49 GMT
2
3
第二次请求:
###################### 请求头 ######################
Cache-Control: max-age=0
If-Modified-Since: Thu, 31 Dec 2020 06:14:49 GMT
If-None-Match: "5fed6c59-a"
###################### 响应码 ######################
304 Not Modified
###################### 响应头 ######################
ETag: "5fed6c59-a"
Last-Modified: Thu, 31 Dec 2020 06:14:49 GMT
2
3
4
5
6
7
8
9
10
# 2.1.4 跨站访问
为什么浏览器禁止跨域访问不安全?容易出现CSRF攻击!
Nginx通过添加Access-Control-Allow-Origin响应头开启跨站访问
Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location
2
3
配置示例
location ~ .*\.(html|htm)$ {
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Origin *;
root /opt/app/html
}
2
3
4
5
# 2.1.5 防盗链
防止资源被盗用
Nginx可以使用http_refer
配置防盗链,该指令会根据Referer Header头的内容分配一个值为0或1给变量$invalid_referer
。如果Referer Header头不符合valid_referers
指令设置的有效Referer,变量$invalid_referer
将被设置为1。
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
2
3
该指令的参数可以为下面的内容:
- none:表示无Referer值的情况。
- blocked:表示Referer值被防火墙进行伪装。
- server_names:表示一个或多个主机名称。0.5.33版本后server_names中可以使用通配符"*"
配置示例
location ~ .*\.(jpg|png|gif)$ {
# 验证规则
valid_referers none blocked server_names
*.example.com example.* www.example.org/galleries/
~\.google\.;
# 校验不通过返回403
if ($invalid_referer) {
return 403;
}
root /opt/app/images;
}
2
3
4
5
6
7
8
9
10
11
# 2.2 代理服务
# 2.2.1 正向代理与反向代理
代理区别在于代理的对象不一样。正向代理代理的对象是客户端,反向代理代理的对象是服务端
正向代理,是在用户端的。比如需要访问某些国外网站,我们可能需要购买vpn。
并且vpn是在我们的用户浏览器端设置的(并不是在远端的服务器设置)。
浏览器先访问vpn地址,vpn地址转发请求,并最后将请求结果原路返回来。
反向代理是作用在服务器端的,是一个虚拟ip(VIP)。对于用户的一个请求,会转发到多个后端处理器中的一台来处理该具体请求。
大型网站都有DNS(域名解析服务器),load balance(负载均衡器)等。
# 2.2.2 代理模式和模块介绍
Nginx可支持的代理协议:
反向代理
常见的Nginx作为反向代理支持的协议:
反向代理模式与Nginx代理模块
反向代理模式 | Nginx配置模块 |
---|---|
http、websocket、https | ngx_http_proxy_module |
fastcgi | ngx_httpfastcgi_module |
uwsgi | ngx_http_uwsgi_module |
grpc | ngx_http_v2_module |
正向代理
常见的Nginx作为正向代理支持的协议
注意:
- 不能支持使用HTTPS协议
- Nginx使用HTTP协议作为正向代理的协议
- Nginx使用正向代理范围比较窄
# 2.2.3 配置语法
Syntax: proxy_pass URL;
Default: —
Context: location, if in location, limit_except
2
3
配置示例
location /name/ {
proxy_pass http://127.0.0.1:8080/$request_uri;
}
2
3
补充配置
1、缓存相关配置
启用或禁用代理服务器响应的缓冲。
Syntax: proxy_buffering on | off;
Default: proxy_buffering on;
Context: http, server, location
2
3
扩展:proxy_buffer size、proxy_buffers、proxy_busy_ buffers_size
2、跳转重定向
修改被代理服务器返回的响应头中的location头域跟refresh头域数值
Syntax: proxy_redirect default;
proxy_redirect off;
proxy_redirect redirect replacement;
Default: proxy_redirect default;
Context: http, server, location
2
3
4
5
https://blog.csdn.net/u010391029/article/details/50395680
3、头信息
更改或新增传递给代理服务器的请求头
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http, server, location
2
3
4
扩展:proxy_hide_header、proxy_set_body
4、超时
定义用于与代理服务器建立连接的超时。请注意,此超时通常不能超过75秒。
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location
2
3
扩展:proxy_read_timeout、proxy_send_timeout
# 2.3 负载均衡调度器SLB
# 2.3.1 负载均衡介绍及划分
按作用范围可划分为 GSLB 和 SLB
1、GSLB(全局负载均衡)
GSLB 是英文Gobal Server Load Balance的缩写,意思是全局负载均衡。
作用:实现在广域网(包括互联网)上不同地域的服务器间的流量调配,保证使用最佳的服务器服务离自己最近的客户,从而确保访问质量。
- 调度中心节点:一个全局的调度节点;
- 调度节点:一个局部调度节点;
- 应用服务中心节点:一个全局的应用服务调度节点;
- 应用服务:一个局部应用服务节点;
调度中心节点管理着调度节点;应用服务中心节点管理着应用服务;
举例:
第一步:张三请求局部调度节点,局部调度节点则返回服务地址给张三; 第二步:张三根据局部调度节点返回的服务地址,请求局部应用服务,局部应用服务则返回结果给张三。
2、SLB(服务器负载均衡)
调度节点与服务节点处于一个逻辑单元里面,这样对于部分服务的实时性、响应性是非常好的。
按七层网络模型课划分为 四层负载均衡 和 七层负载均衡
1、四层负载均衡,即传输层负载均衡
按照网络OSI模型可以分为四层负载均衡和七层负载均衡;
四层负载均衡:在OSI模型里面的传输层,传输层能支持到tcp/ip协议,所以只需要转发tcp/ip协议的包,就可以实现负载均衡。
优势:性能非常好,只需要在最底层应用处理,而不需要进行一些复杂的逻辑,只需要包的转发就行
2、七层负载均衡,处理应用层,如:http信息
七层负载均衡主要是在应用层使用,所以它可以完成很多应用层的协议请求,比如HTTP协议的负载均衡,它可以实现HTTP信息的改写,头信息的改写,应用规则的控制。
Nginx是典型的七层负载均衡SLB。
# 2.3.2 Nginx负载均衡配置
Nginx负载均衡配置是基于 proxy_pass 和 upstream 实现的。如下图:upstream server就相当于配置的虚拟服务池。
upstream配置
定义一组服务器。服务器可以在不同的端口上侦听。此外,可以混合使用侦听TCP和UNIX域套接字的服务器。
Syntax: upstream name { ... }
Default: —
Context: http
2
3
配置示例
# 定义一组服务器
upstream lucifer {
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
server {
listen 80;
location / {
# 使用upstream定义的服务器组负载均衡
proxy_pass http://lucifer
}
......
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream详解
官方示例
upstream backend {
# 加权重
server backend1.example.com weight=5;
# 指定最大失败次数和暂停服务时间
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
# socket方式
server unix:/tmp/backend3;
# 备份节点
server backup1.example.com backup;
}
2
3
4
5
6
7
8
9
10
附加配置项含义:
配置 | 含义 |
---|---|
down | 当前的server暂时不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后,服务暂停的时间 |
max_conns | 限制最大的接收的连接数 |
# 2.3.3 Nginx调度算法
调度方式 | 解释 |
---|---|
轮询 | 按时间顺序逐一分配到不同的后端服务器 |
加权轮询 | weight值越大,分配到的访问几率越高 |
ip_hash | 每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器 |
url_hash | 按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器 |
least_conn | 最少链接数,那个机器连接数少就分发 |
hash关键数值 | hash自定义的key |
1、weight加权轮询配置
upstream lucifer {
server 127.0.0.1:8081;
server 127.0.0.1:8082 weight=5;
server 127.0.0.1:8083;
}
2
3
4
5
2、ip_hash配置
upstream lucifer {
ip_hash;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
2
3
4
5
6
3、url_hash配置
upstream lucifer {
hash $request_uri;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
server 127.0.0.1:8083;
}
2
3
4
5
6
# 2.4 动态缓存
# 2.4.1 缓存分类和代理缓存
缓存可分为服务端缓存、代理缓存、客户端缓存,Nginx配置缓存是代理缓存。
Nginx代理缓存生效流程:
- 客户端第一次向Nginx请求数据a;
- 当Nginx发现缓存中没有数据a时,会向服务端请求数据a;
- 服务端接收到Nginx发来的请求,则返回数据a到Nginx,并且缓存在Nginx;
- Nginx返回数据a给客户端应用;
- 客户端第二次向Nginx请求数据a;
- 当Nginx发现缓存中存在数据a时,则不会请求服务端,直接将缓存中的数据放回给客户端。
# 2.4.2 缓存配置
1、proxy_cache_path
设置缓存的路径和其他参数。
Syntax: proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [min_free=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
Default: —
Context: http
2
3
2、proxy_cache
定义用于缓存的共享内存区域。
Syntax: proxy_cache zone | off;
Default: proxy_cache off;
Context: http, server, location
2
3
3、proxy_cache_valid
为不同的响应状态码设置缓存时间。
Syntax: proxy_cache_valid [code ...] time;
Default: —
Context: http, server, location
2
3
4、proxy_cache_key
定义用于缓存的key。
Syntax: proxy_cache_key string;
Default: proxy_cache_key $scheme$proxy_host$request_uri;
Context: http, server, location
2
3
5、proxy_no_cache
配置不缓存的条件。如果字符串参数中至少有一个值不为空且不等于“0”,则不会缓存响应。
Syntax: proxy_no_cache string ...;
Default: —
Context: http, server, location
2
3
7、配置实例
# 定义服务器组
upstream lucifer {
server 116.62.103.228:8001;
server 116.62.103.228:8002;
server 116.62.103.228:8003;
}
# 缓存路径 缓存目录层次结构级别 定义key空间名和大小 目录最大容量 不活跃失效时间 关闭临时文件
proxy_cache_path /opt/app/cache levels=1:2 keys_zone=lucifer_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
# 如果请求uri符合条件,则设置$cookie_nocache值为1
if($request_uri ~ ^/(url3|login|register|password\/reset)) {
set $cookie_nocache 1;
}
location / {
# 使用定义的key空间
proxy_cache lucifer_cache;
proxy_pass http://lucifer;
# 针对不同的响应状态码设置缓存时间
proxy_cache_valid 200 304 12h;
proxy_cache_valid any 10m;
# 设置缓存key
proxy_cache_key $host$uri$is_args$args;
# 加入头信息以直观感受是否命中缓存
add_header Nginx-Cache "$upstream_cache_status";
# 配置不缓存的条件,只要有一个参数不为0,就不缓存
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_no_cache $http_pragma $http_authorization;
# 配置出现指定错误时,跳过本台服务器去尝试下一台服务器
proxy_next_upstream error timeout invalid_header http_ 500 http_502 http_503 http_504;
}
}
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
8、场景配置补充说明
如何清理指定缓存?
- 方式一:rm -rf 缓存目录内容
- 方式二:第三方扩展模块ngx_cache_purge
# 2.4.3 请求分片
ngx_http_slice_module模块将一个请求拆分为子请求,每个子请求返回一定范围的响应。
默认情况下不生成此模块,应使用--with-http\u slice\u module配置参数启用它。
- 优点:每个子请求收到的数据都会形成一个独立的文件,一个请求断了,其他请求不会收到影响。
- 缺点:当文件很大或者slice设置很小时,可能会导致文件描述符耗尽等情况。
配置语法:
Syntax: slice size;
Default: slice 0;
Context: http, server, location
2
3
配置实例:
location / {
slice 1m;
proxy_cache cache;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
proxy_pass http://localhost:8000;
}
2
3
4
5
6
7
8
此示例中,响应被分为1m的可缓存片。