5.Nginx 反向代理
反向代理:reverse proxy,指的是代理外网用户的请求到内部指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式
nginx 除了可以在企业提供高性能的 web 服务之外,还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其他服务器处理,不同的协议就是 nginx 服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能
1 | # 将客户端的请求以http协议转发至指定服务器进行处理 |
逻辑调用关系:
生成环境部署结构:
访问逻辑图:
http 反向代理
反向代理配置参数
proxy_pass
设置后端服务器的协议和地址,协议支持 http 和 https,地址既可以是域名也可以是 ip,还可以配置端口
语法: proxy_pass URL;
默认值: —
上下文: location, if in location, limit_exceptURL 分为两种:结尾加”/“和结尾不加”/“,如果不加”/“,proxy_pass 类似 root,如果加”/“,proxy_pass 类似 alias
范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14location /web {
# http://to2b.cn/web/index.html ==> http://127.0.0.0.1:8080/web/index.html
proxy_pass http://127.0.0.1:8080
}
location /web {
# http://to2b.cn/web/index.html ==> http://127.0.0.0.1:8080/index.html
proxy_pass http://127.0.0.1:8080/
}
# 如果location定义uri时使用了正则表达式模式(包括~和~*),则结尾不能加"/"
location ~|~* /uri/ {
proxy_pass http://host:port; # proxy_pass后面的url 不能加/
}proxy_hide_header
nginx 作为反向代理服务器时,在返回给客户端 http 响应时,隐藏后端服务器响应头的信息
语法: proxy_hide_header field;
默认值: —
上下文: http, server, location示例:隐藏后端服务器的 ETag 首部字段
1
2
3
4
5location /web {
index index.html;
proxy_pass http://10.0.0.18:8080/;
proxy_hide_header ETag;
}proxy_pass_header
允许传送被屏蔽的后端服务器响应头到客户端。
默认 nginx 在响应报文中不传递后端服务器的首部字段 Date, Server, X-Pad, X-Accel 等参数,如果要传递的话则要使用
proxy_pass_header field
声明将后端服务器返回的值传递给客户端field 首部字段大小不敏感
语法: proxy_pass_header field;
默认值: —
上下文: http, server, locationproxy_pass_request_body
是否向后端服务器发送 HTTP 实体部分,默认开启
Syntax: proxy_pass_request_body on | off;
Default: proxy_pass_request_body on;
Context: http, server, locationproxy_pass_request_headers
是否将客户端的请求头部转发给后端服务器
Syntax: proxy_pass_request_headers on | off;
Default: proxy_pass_request_headers on;
Context: http, server, locationproxy_set_header
可更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实 IP 的时候,就要更改每一个报文的头部
语法: proxy_set_header field value;
默认值: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
上下文: http, server, location示例:
1
2proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;proxy_connect_timeout
配置 nginx 服务器与后端服务器尝试建立连接的超时时间,默认为 60 秒,超时会返回客户端 504 响应码
语法: proxy_connect_timeout time;
默认值: proxy_connect_timeout 60s;
上下文: http, server, location示例:
1
proxy_connect_timeout 6s;
proxy_read_timeout
定义从后端服务器读取响应的超时。此超时是指相邻两次读操作之间的最长时间间隔,而不是整个响应传输完成的最长时间。如果后端服务器在超时时间段内没有传输任何数据,连接将被关闭
语法: proxy_read_timeout time;
默认值: proxy_read_timeout 60s;
上下文: http, server, locationproxy_send_timeout
定义向后端服务器传输请求的超时。此超时是指相邻两次写操作之间的最长时间间隔,而不是整个请求传输完成的最长时间。如果后端服务器在超时时间段内没有接收到任何数据,连接将被关闭
语法: proxy_send_timeout time;
默认值: proxy_send_timeout 60s;
上下文: http, server, locationproxy_http_version
语法: proxy_http_version 1.0 | 1.1;
默认值: proxy_http_version 1.0;
上下文: http, server, location设置代理使用的 HTTP 协议版本。默认使用的版本是 1.0,而 1.1 版本则推荐在使用 keepalive 连接时一起使用
proxy_ignore_client_abort
决定当客户端在响应传输完成前就关闭连接时,nginx 是否应关闭后端连接,默认为 off
当客户端网络中断请求时,nginx 服务器中断其对后端服务器的请求。即如果设置 on 开启,服务器会忽略客户端中断并一直等着代理服务执行返回,如果设置 off,则客户端中断后 Nginx 也会中断客户端请求并立即记录 499 日志
语法: proxy_ignore_client_abort on | off;
默认值: proxy_ignore_client_abort off;
上下文: http, server, locationproxy_headers_hash_bucket_size
当配置了 proxy_hide_header 和 proxy_set_header 的时候,用于设置 nginx 保存 HTTP 报文头的 hash 表的上限,默认 64 字节
示例:
1
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size
设置 proxy_headers_hash_bucket_size 的最大可用空间,默认 512 字节
server_names_hash_bucket_size
server_name hash 表申请空间大小
server_names_hash_max_size
设置服务器名称 hash 表的上限大小
缓存 proxy_buffering 和 proxy_cache
为了方便,我们定义三个角色:A 客户端 browser、B 代理服务器 Nginx,C 被代理服务器 PHP
proxy_buffering:缓冲,实现被代理服务器的数据和客户端的请求异步,A发起请求到B,B再去请求C,C反馈的数据先到 B 的 buffer 上
proxy_cache:缓存,B 将从 C 获取到的数据缓存起来,之后 A 再请求时,直接将缓存的数据返回,而不必再向 C 去获取
缓冲
proxy_buffering
开启缓冲,默认开启,如果不开启,C 返回的数据实时的通过 B 发送给 A
proxy_buffering 如果设置为 off,proxy_buffers 和 proxy_busy_buffers_size 这两个指令将会失效
proxy_buffers
设置 B 的缓冲区占用的 buffer 的个数和每个 buffer 的大小,所以缓冲区的大小为这两个数字的乘积
示例:
1
proxy_buffers 8 4k; # 缓冲区总的大小为32k
proxy_busy_buffers_size
proxy_busy_buffers_size 通常设置为两个 buffer 的大小,示例:
1
proxy_busy_buffers_size 8k;
上例中,proxy_busy_buffers_size 设置为 8K,如果返回的数据小于 8K,则 B 从 C 请求的数据全部到位后,一次性返回给 A;如果返回的数据大于 8K,则 B 从 C 请求的数据分每次 8K 返回给 A,例如一共 20K 数据,分 8K、8K、4K 三次返回给 A
proxy_buffer_size
该参数用来设置一个特殊 buffer 大小,C 到 B 的第一部分相应数据就存在这个 buffer 中,通常是 header,如果该参数设置太小,会出现 502 错误,不论 proxy_buffering,是否生效,proxy_buffer_size 都生效
示例:
1
proxy_buffer_size 4k; # 通常设置为单个buffer的大小
proxy_temp_path
缓冲区的容量毕竟有限,如果并发请求太多,响应的数据量太大,超出缓冲区的数据会储存在临时目录下
proxy_temp_path 定义临时目录
语法: proxy_temp_path path [level1 [level2 [level3]]];
默认值: proxy_temp_path proxy_temp;
上下文: http, server, location至多设置三层子目录,目录的命名规则和 client_body_temp_path 一样
proxy_max_temp_file_size
临时文件的最大容量,默认 1024m,也就是 1G
proxy_temp_file_write_size
每次写入临时文件的数据量, 通常和 proxy_busy_buffers_size 设置的值一样,两个 buffer 的大小
缓存
proxy_cache
指定用于页面缓存的共享内存。同一块共享内存可以在多个地方使用。off 参数可以屏蔽从上层配置继承的缓存功能
语法: proxy_cache zone | off;
默认值: proxy_cache off;
上下文: http, server, locationzone 是缓存区域的名称,需要 proxy_cache_path 事先定义
proxy_cache_path
语法: proxy_cache_path path [levels=levels] keys_zone=name:size [inactive=time] [max_size=size] [loader_files=number] [loader_sleep=time] [loader_threshold=time];
默认值: —
上下文: http示例:
1
2
3
4
5
6
7proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_size=1g
# /var/cache/nginx/proxy_cache 定义缓存保存路径,proxy_cache会自动创建
# levels=1:2:2 定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录
# keys_zone=proxycache:20m 内存中缓存的大小,主要用于存放key和metadata
# inactive=120s 缓存有效时间
# max_size=1g 最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值proxy_cache_key
定义如何生成缓存的键,默认值就挺好,一般不用设置
语法: proxy_cache_key string;
默认值: proxy_cache_key $scheme$proxy_host$request_uri;
上下文: http, server, locationproxy_cache_valid
为不同的响应状态码设置不同的缓存时间
语法: proxy_cache_valid [code …] time;
默认值: —
上下文: http, server, location示例:
1
2
3proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;proxy_cache_use_stale
如果后端服务器出现状况,nginx 可以使用过期的响应缓存。这条指令就是定义何种条件下允许开启此机制
语法: proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_404 | off …;
默认值: proxy_cache_use_stale off;
上下文: http, server, location示例:
1
proxy_cache_use_stale error http_502 http_503;
proxy_cache_methods
对哪些客户端请求方法对应的响应进行缓存,虽然 GET 和 HEAD 方法总是被缓存,但是建议显式的指定
示例:
1
proxy_cache_methods GET | HEAD | POST ...;
添加头部报文信息
基于模块 ngx_http_headers_module,可以实现对后端服务器响应给客户端的报文中添加指定的响应首部字段
Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location
示例:
1 | add_header X-Via $server_addr; # 当前nginx主机的IP |
反向代理高级应用
基于 ngx_http_upstream_module 模块,实现服务器分组转发、权重分配、状态监测、调度算法等高级功能
upstream
定义一组服务器。 这些服务器可以监听不同的端口。 而且,监听在 TCP 和 UNIX 域套接字的服务器可以混用
语法: upstream name { … }
默认值: —
上下文: http示例:
1
2
3
4
5upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}server
在 upstream 内,至少要有一个 server 服务器配置
语法: server address [parameters];
默认值: —
上下文: upstream定义服务器的地址和其他参数,地址可以是域名、ip、unix 套接字,如果没有指定端口,默认 80 端口
如果一个域名解析到了多个 ip,本质就是在 upstream 定义了多个 server
parameters:
- weight=number:设定服务器的权重,默认是 1
- max_conns=number:给当前 server 设置最大活动链接数,默认为 0 表示没有限制
- max_fails=number:fail_timeout 规定时间内,对后端服务器连续监测失败的次数,超过则标记为不可用,默认为 1 次,当客户端访问时,才会利用 TCP 触发对探测后端服务器健康性检查,而非周期性的探测
- fail_timeout=time:fail_timeout 时间内,连续监测失败 max_fails 次;或者 fail_timeout 时间内,一直监测失败,则标记服务器不可用
- backup:标记为备用服务器,当其他服务器都不可用时,才会启用此服务器
- down:标记为 down 状态
- resolve:如果 server 定义的是主机名,当 A 记录发生变化会自动应用新 IP 而不用重启 Nginx
- …
示例:
1
2
3
4
5
6
7upstream backend {
server backend1.example.com weight=5;
# 30s内,对后端服务器连续监测失败3次,标记次服务器不可用
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
}hash
Syntax: hash key [consistent];
Default: —
Context: upstream基于指定的 key 做 hash 计算,key 来自请求报文中首部字段或者 URI,consistent 定义使用一致性 hash 运算,一
致性 hash 基于取模运算,适用于后端是 Cache 服务器(如 varnish)时使用示例:
1
2hash $request_uri consistent; # 基于用户请求的uri做hash
hash $cookie_sessionid; # 基于cookie中的sessionid这个key进行hash调度,实现会话绑定ip_hash
源地址 hash 调度方法,基于的客户端的 remote_addr(源地址 IPv4 的前 24 位或整个 IPv6 地址)做 hash 计算,以实现会话保持
least_conn
最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于 LVS 中的 WLC
示例:
1 | http { |
反向代理客户端 IP 透传
1 | # 第一个代理服务器 10.0.0.8 |
基于 Cookie 实现会话绑定
nginx 把客户端的请求轮询到不同的服务器,对于已经登录的客户端(用户信息储存在 cookie),就不适合轮询了,应该始终访问储存登录信息的那台服务器
1 | http { |
tcp 负载均衡
基于 ngx_stream_proxy_module 模块,允许通过 TCP、UDP、和 unix 域套接字代理数据流,nginx1.9.0 版本支持
编译安装需要添加 –with-stream 编译选项
stream
没有在官方文档中找到这个参数,但是它确实存在,和 http 同级别,位于 main 上下文
负载均衡 redis
1 | stream { |
负载均衡 mysql
1 | stream { |
FastCGI
CGI 和 FastCGI
最早的 web 服务器只能处理静态文件,对于 php、java 这样的动态语言文件,apache 实现的方式是打补丁,nginx 则通过某种特定的协议将客户端请求转发给语言解析器,这个特定的协议就是 CGI(通用网关接口 common gateway interface),语言解析器新建进程处理请求
CGI 协议解决了语言解析器和 web 服务器之间通讯的问题,但是它的效率太低,因为每处理一个请求,就要新建进程,处理完之后就销毁进程,而 FastCGI 解决了这个问题,每次处理完请求后不会关闭进程,等待处理下一个进程,直到超时没有任务才会被销毁
php-fpm
FastCGI Process Manager,FastCGI 进程管理器,是一个实现了 FastCGI 的程序,提供进程管理功能,进程包括 master 进程和 worker 进程。master 进程只有一个,负责监听端口,接受来自 web server 的请求。worker 进程一般会有多个,每个进程中会嵌入一个 PHP 解析器,进行 PHP 代码的处理
FastCGI 配置指令
1 | fastcgi_pass address:port; # 请求转发到后端服务器,指定后端服务器的地址和端口 |
动静分离
1 | # 静态文件 |