Nginx负载均衡和反向代理

负载均衡

image-20240323183038173

负载均衡:Nginx 的负载均衡是保障服务可用性的重要手段。当服务异常或者处于扩容中无法提供服务时,可以让请求绕过这些节点。

Nginx 在 AKF 扩展立方体上的应用

image-20240323183226774

  • X:基于 Round-Robin 或者 least-connected 算法分发请求
  • Y:基于 URL 对功能进行分发
  • X:将用户 IP 地址或者其他信息映射到某个特定的服务或者集群

支持多种协议的反向代理

image-20240323183513511

  • 四层代理:依靠 IP地址实现,通过 stream 模块支持,将下游发过来的 TCP、UDP 请求转发出去
  • 七层代理:依靠业务信息,例如 Header、Method、URI 之类的,可以将 HTTP 请求作为 memcachedscgi 等协议的请求转发到上游

反向代理与缓存

image-20240323185955285

缓存可以分为两类:

  • 时间缓存:将上游应用服务器的响应缓存在 Nginx 服务器的磁盘上,当下次同样的请求到达 Nginx 时,则直接返回磁盘上的内容。
  • 空间缓存:当 Nginx 访问上游服务器时,可以预取一些内容缓存到 Nginx 磁盘

指定上游服务地址的 upstream 与 server 指令

Nginx 中将负责与上游服务交互的模块统称为 upstream 模块,包括 streamhttp_upstream。并且提供 rb 负载均衡算法。

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream

1
2
3
4
5
6
7
8
9
# name 会交由后面的反向代理使用
# {} 包含一个应用服务集群,会包含很多 server
Syntax: upstream name { ... }
Default: —
Context: http

Syntax: server address [parameters];
Default: —
Context: upstream

功能:指定一组上游服务器地址,其中,地址可以是域名、IP 地址或者 unix socket 地址。可以在域名或者 IP 地址后加端口,如果不加端口,那么默认使用 80 端口。

通用参数:

  • backup:指定当前 server 为备份服务,仅当非备份 server 不可用时,请求才会转发到该 server
  • down:标识某台服务已经下线,不在服务(主要方便管理和维护)
1
2
3
4
5
6
7
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;

server backup1.example.com backup;
}

加权 Round-Robin 负载均衡算法

功能:在加权轮询的方式询问 server 指令指定的上游服务。默认集成在 Nginx 的 upstream 框架中。

指令:

  • weight:服务访问的权重,默认是 1
  • max_connsserver 的最大并发连接数,仅作用于单 worker 进程。默认是 0,表示没有限制
  • max_fails:在 fail_timeout 时间段内,最大的失败次数。当达到最大失败时,会在 fail_timeout 秒内这台 server 不允许再次被选择
  • fail_timeout:单位为秒,默认 10 秒,具有两个功能:
    • 指定一段时间内,也是 fail_timeout,最大的失败次数 max_fails
    • 到达 max_fails 后,该 server 不能访问的时间

对上游服务使用 keepalive 长连接

功能:通过复用连接,降低 Nginx 与上游服务器建立、关闭连接的消耗,提升吞吐量的同时,降低时延(上游服务器数量有限,效果更好)

对上游连接的 http 头部增加设定:

1
2
proxy_http_version 1.1; # http 1.0 协议不支持,为了防止用户发来的是 1.0 版本协议,设置覆盖 1.1
proxy_set_header Connection ""; # 为了防止用户请求header 中 Connection 是 close,而不是 keep-alive,设置覆盖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 配置 Nginx 到上游配置的服务器,每个工作进程最多保持多少个空闲的连接用于 keepalive 请求
Syntax: keepalive connections;
Default: —
Context: upstream
This directive appeared in version 1.1.4.

# 一条 TCP 连接上最多跑多少个请求
Syntax: keepalive_requests number;
Default:
keepalive_requests 1000;
Context: upstream
This directive appeared in version 1.15.3.

# 一个 TCP 连接在处理完请求后,最多 60s 没有请求就关闭 TCP 连接
Syntax: keepalive_timeout timeout;
Default:
keepalive_timeout 60s;
Context: upstream
This directive appeared in version 1.15.3.

指定上游服务域名解析

resolver 指令,解析上游服务域名,以及域名解析超时时间

1
2
3
4
5
6
7
8
9
10
Syntax:    resolver address ... [valid=time] [ipv4=on|off] [ipv6=on|off] [status_zone=zone];
Default: —
Context: upstream
This directive appeared in version 1.17.5.

Syntax: resolver_timeout time;
Default:
resolver_timeout 30s;
Context: upstream
This directive appeared in version 1.17.5.

基于客户端 IP 地址的 Hash 算法实现负载均衡

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash

ip_hash 功能:以客户端的 IP 地址(remote-addr)作为 hash 算法的关键字,映射到特定的上游服务器中。

  • 对 IPv4 地址使用前 3 个字节作为关键字,对 IPv6 则使用完整地址(16个字节)
  • 可以使用 round-robin 算法的参数
  • 可以基于 realip 模块修改用于执行算法的 IP 地址
1
2
3
Syntax:    ip_hash;
Default: —
Context: upstream

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#hash

hash 功能:通过指定关键字作为 hash key,基于 hash 算法映射到特定的上游服务器中。

  • 关键字可以含有变量、字符串
  • 可以使用 round-robin 算法的参数
1
2
3
4
Syntax:    hash key [consistent];
Default: —
Context: upstream
This directive appeared in version 1.7.2.
1
2
3
4
5
6
7
8
upstream backend {
ip_hash;

server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}

hash 算法的问题

当上游服务器异常、扩容、缩容时,hash 算法会引发大量路由变更,可能导致缓存大范围失效。

image-20240323195231676

缩容后:

image-20240323195242671

一致性 hash 算法

在一个环上获取放置节点,当扩容或者缩容,可以将部分流量迁移到其他流量,而不是所有流量。

image-20240323195342578

扩容后:

image-20240323195424185
1
2
3
4
Syntax:    hash key [consistent];
Default: —
Context: upstream
This directive appeared in version 1.7.2.

使用 consistent 开启一致性哈希算法。

优先选择连接最少的上游服务器

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#least_conn

从所有上游服务器中,找出当前并发连接数最少的一个,将请求转发到它。

  • 如果出现多个最少连接服务器的连接数都是一样的,使用 round-robin 算法。
1
2
3
4
Syntax:    least_conn;
Default: —
Context: upstream
This directive appeared in versions 1.3.1 and 1.2.2.

使用共享内存使负载均衡策略对所有 worker 进程生效

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone

分配出共享内存,将其他 upstream 模块定义的负载均衡策略数据、运行时每个上游服务的状态(连接数、权重、失败次数)存放在共享内存上,以对所有 nginx worker 进程生效。

1
2
3
4
Syntax:    zone name [size];
Default: —
Context: upstream
This directive appeared in version 1.9.0.

upstream 模块间的顺序

保障功能的正常运行

1
2
3
4
5
6
7
8
9
10
ngx_module_t *ngx_modules[] = { 
......
&ngx_http_upstream_hash_module,
&ngx_http_upstream_ip_hash_module,
&ngx_http_upstream_least_conn_module,
&ngx_http_upstream_random_module,
&ngx_http_upstream_keepalive_module,
&ngx_http_upstream_zone_module,
......
};

upstream 模块提供的变量(不含 cache)

  • upstream_addr:上游服务器的 IP 地址,格式为可读的字符串,例如 192.168.1.1:80
  • upstream_connect_time:与上游服务建立连接消耗的时间,单位为 秒,精确到毫秒
  • upstream_header_time:接收上游服务发回响应中 http 头部所消耗的时间(响应先返回 header),单位为秒,精确到毫秒
  • upstream_response_time:接收完整的上游服务响应所消耗的时间,单位为秒,精确到毫秒
  • upstream_http_名称:从上游服务返回的响应头部的值
  • upstream_bytes_received:从上游服务接收到的响应长度,单位为字节
  • upstream_response_length:从上游服务返回的响应包体长度,单位为字节
  • upstream_status:上游服务返回的 HTTP 响应中的状态码。如果未连接上,该变量值为 502
  • upstream_cookie_名称:从上游服务发回的响应头 Set-Cookie 中取出的 cookie
  • upstream_trailer_名称:从上游服务的响应尾部取到的值

反向代理

流程

image-20240324001446617

  1. 当缓存未命中,与上游服务器发送请求时,是先生成请求 headerbody,甚至会读取请求完整的 body(是否读取请求完整的 body 依据 proxy_request_buffering 参数,默认打开,也就是缓存到磁盘上),然后根据负载均衡策略连接上游服务器(避免上游服务器并发不强时产生影响)
  2. 上游服务发回响应是先发送 header,Nginx 先处理响应头部,再决定如何处理 body。如果 proxy_buffering on (默认),则接收完整的响应包体之后,再发送响应包体。

Proxy 模块

对上游服务使用 http/https 协议进行反响代理。默认编译进 Nginx

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass

1
2
3
Syntax:    proxy_pass URL;
Default: —
Context: location, if in location, limit_except

URL 参数规则

  • URL 必须以 http:// 或者 https:// 开头,接下来是域名、IPunix socket 地址或者 upstream 的名字(代表一个集群),前两者可以在域名或者 IP 后加端口。最后时可选的 URI
  • 当 URL 参数中携带 URL 与否,会导致发向上游请求的 URL 不同:
    • 不携带 URL,则将客户端请求中的 URL 直接转发给上游
      • location 后使用正则表达式、@名字时,应采用这种方式
    • 携带 URL,则对用户请求中的 URL 做如下操作:
      • location 参数中匹配上的一段替换为该 URI
  • 该 URI 参数中可以携带变量
  • 更复杂的 URL 替换,可以在 location 内的配置添加 rewrite break 语句
1
2
3
4
5
6
# 例如下面,在端口后面有内容,就是携带 URL,此时请求 /xxx/abc,则会请求到上游的 /uri/abc
# 也就是 /xxx 被替换成 /uri
proxy_pass http://localhost:8000/uri;

# 下面这个不带 URL,请求 /xxx/abc,则会请求上游的 /xxx/abc
proxy_pass http://localhost:8000;

根据指令修改发往上游的请求

生成请求行

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_method

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 设置 method
Syntax: proxy_method method;
Default: —
Context: http, server, location

# 修改 http version
Syntax: proxy_http_version 1.0 | 1.1;
Default:
proxy_http_version 1.0;
Context: http, server, location
This directive appeared in version 1.1.4.

# 若 value 的值为空字符串,则整个 header 都不会向上游发送
Syntax: proxy_set_header field value;
Default:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http, server, location

# 是否向上游发送 header
Syntax: proxy_pass_request_headers on | off;
Default:
proxy_pass_request_headers on;
Context: http, server, location

生成包体

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_body

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_body

1
2
3
4
5
6
7
8
9
10
# 是否将用户请求中的 body 传递给上游
Syntax: proxy_pass_request_body on | off;
Default:
proxy_pass_request_body on;
Context: http, server, location

# 手动构造发往上游的 body
Syntax: proxy_set_body value;
Default: —
Context: http, server, location

Nginx 接收请求包体的方式

收完再转发还是边收边转发。

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_request_buffering

1
2
3
4
5
Syntax:    proxy_request_buffering on | off;
Default:
proxy_request_buffering on;
Context: http, server, location
This directive appeared in version 1.7.11.

启用或禁用客户端请求主体的缓冲。

当启用缓冲时,整个请求主体从客户端读取后再发送给代理服务器。

当禁用缓冲时,请求主体在接收到后立即发送给上游服务器。在这种情况下,如果 nginx 已经开始发送请求主体,则无法将请求传递给下一个服务器。当使用 HTTP/1.1 分块传输编码来发送原始请求主体时,除非为代理启用了 HTTP/1.1,否则不管指令值如何都会对请求主体进行缓冲。

  • on:接收完再转发,将 body 缓存在磁盘中
    • 客户端网速慢
    • 上游服务并发处理能力低
    • 适应高吞吐量场景(打开之后,非常依赖 Nginx 的高吞吐能力)
  • off:边接收边转发
    • 更及时的响应
    • 降低 Nginx 读写磁盘的消耗
    • 一旦开始发送内容,proxy_next_upstream 功能失败

客户端包体的接收

https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

1
2
3
4
5
6
7
8
9
Syntax:    client_body_buffer_size size;
Default:
client_body_buffer_size 8k|16k;
Context: http, server, location

Syntax: client_body_in_single_buffer on | off;
Default:
client_body_in_single_buffer off;
Context: http, server, location

客户端发过来的请求中存在包体时,接收包体所分配的内存

  • 若接收头部时已经接收完全部包体,则部分配(接收 header 时,可能也接收到了一点包体)
  • 若剩余待接收包体的长度小于 client_body_buffer_size,则仅分配所需大小
  • 分配 client_body_buffer_size 大小内存接收包体
    • 关闭包体缓存时,该内存上内容及时发送给上游
    • 打开包体缓存
      • 该段大小内存用完时,写入临时文件,释放内存

最大包体长度限制

1
2
3
4
Syntax:    client_max_body_size size;
Default:
client_max_body_size 1m;
Context: http, server, location

仅对请求头部中含有 Content-Length 有效超出最大长度后,返回 413 错误。

临时文件路径格式

1
2
3
4
5
6
7
8
9
10
11
12
13
# 设置在哪个目录下放置 body,Nginx 启动后,默认会创建这个目录
# 多级子目录解决同目录下文件过多导致响应慢的问题
Syntax: client_body_temp_path path [level1 [level2 [level3]]];
Default:
client_body_temp_path client_body_temp;
Context: http, server, location

# 包体是否必须存放在文件中,主要用于定位问题
# on 代表文件不删除
Syntax: client_body_in_file_only on | clean | off;
Default:
client_body_in_file_only off;
Context: http, server, location

读取包体时的超时

1
2
3
4
Syntax:    client_body_timeout time;
Default:
client_body_timeout 60s;
Context: http, server, location

读取包体时超时,则返回 408 错误。

向上游服务建立连接

https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_connect_timeout

1
2
3
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location

超时后,会向客户端生成 http 响应,响应码为 502(如果路由失效,不会等待 60s)

1
2
3
4
Syntax:    proxy_next_upstream on | off;
Default:
proxy_next_upstream on;
Context: stream, server

当无法与代理服务器建立连接时,确定客户端连接是否将传递到下一个服务器。

上游连接启用 TCP keepalive

1
2
3
4
5
Syntax:    proxy_socket_keepalive on | off;
Default:
proxy_socket_keepalive off;
Context: stream, server
This directive appeared in version 1.15.6.

TCP keepalive 是用于 TCP 连接,当没有数据传输时,会通过定时发送探测包,维护 TCP 连接。(由操作系统实现)

image-20240324113820069

上游连接启用 HTTP keepalive

https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

1
2
3
4
5
6
7
8
9
10
Syntax:    keepalive connections;
Default: —
Context: upstream
This directive appeared in version 1.1.4.

Syntax: keepalive_requests number;
Default:
keepalive_requests 1000;
Context: upstream
This directive appeared in version 1.15.3.

使用了 HTTP 的 keepalive,大多数时候可以覆盖 TCP 的 keepalive

修改 TCP 连接中的 local address

https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_bind

1
2
3
4
Syntax:    proxy_bind address [transparent] | off;
Default: —
Context: stream, server
This directive appeared in version 1.9.2.
  • 可以使用变量:
    • proxy_bind $remote_addr;
  • 可以使用不属于所在机器的 IP 地址:(需要有 root 权限)
    • proxy_bind $remote_addr transparent;

使用场景:

  1. 如果到达上游服务器有多个路由,proxy_bind 可以指定 IP,而不使用系统路由
  2. 透传 IP 地址

proxy_bind 其实是在修改 IP 报文中的 Source IP Address

image-20240324114609246

当客户端关闭连接时

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort

1
2
3
4
Syntax:    proxy_ignore_client_abort on | off;
Default:
proxy_ignore_client_abort off;
Context: http, server, location

当下游客户端出现失败,关闭客户端到 nginx 的连接,proxy 是否要忽略这个报错,是否一并关闭。

向上游发送 HTTP 请求

1
2
3
4
Syntax:    proxy_send_timeout time;
Default:
proxy_send_timeout 60s;
Context: http, server, location

Nginx 从接收到客户端请求,到生成请求,将请求发送给上游的超时时间。

接收上游的响应

接收上游的 HTTP 响应头部

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffer_size

1
2
3
4
Syntax:    proxy_buffer_size size;
Default:
proxy_buffer_size 4k|8k;
Context: http, server, location

这个值也限制了 header 的大小,如果 header 中携带 cookie,超过了 proxy_buffer_size,那么 Nginx 无法正常处理这个请求。

出现这个问题时,Nginx 日志中会出现:error.log: upstream sent too big header

接收上游的 HTTP 包体

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffers

1
2
3
4
Syntax:    proxy_buffers number size;
Default:
proxy_buffers 8 4k|8k;
Context: http, server, location

当指定大小的内存能存放上游的包体,则不会向磁盘中写入。

1
2
3
4
Syntax:    proxy_buffering on | off;
Default:
proxy_buffering on;
Context: http, server, location

启用或禁用来自代理服务器的响应缓冲。

  • 当启用缓冲时,nginx 尽快从代理服务器接收响应,并将其保存到由 proxy_buffer_sizeproxy_buffers 指令设置的缓冲区中。如果整个响应无法完全放入内存,则部分内容可以保存到磁盘上的临时文件中。写入临时文件受 proxy_max_temp_file_sizeproxy_temp_file_write_size 指令控制。
  • 当禁用缓冲时,响应会同步传递给客户端,即在接收到后立即传递。Nginx 不会尝试从代理服务器读取整个响应。Nginx 一次从服务器接收数据的最大大小由 proxy_buffer_size 指令设置。也可以通过在 X-Accel-Buffering 响应头字段中传递 yesno 来启用或禁用缓冲功能。此功能可通过使用 proxy_ignore_headers 指令进行禁用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Syntax:    proxy_max_temp_file_size size;
Default:
proxy_max_temp_file_size 1024m;
Context: http, server, location

Syntax: proxy_temp_file_write_size size;
Default:
proxy_temp_file_write_size 8k|16k;
Context: http, server, location

Syntax: proxy_temp_path path [level1 [level2 [level3]]];
Default:
proxy_temp_path proxy_temp;
Context: http, server, location

及时转发包体

1
2
3
4
Syntax:    proxy_busy_buffers_size size;
Default:
proxy_busy_buffers_size 8k|16k;
Context: http, server, location

虽然缓存响应,但是也希望更及时向客户端发送响应。此时收到 8k|16k(与机器相关)时,则转发给客户端。

接收上游时网络速度相关指令

1
2
3
4
5
6
7
8
9
10
11
12
# 两次读取上游响应操作之间的超时时间
Syntax: proxy_read_timeout time;
Default:
proxy_read_timeout 60s;
Context: http, server, location

# 限速,限制读取上游的响应,默认为0,表示不限速
Syntax: proxy_limit_rate rate;
Default:
proxy_limit_rate 0;
Context: http, server, location
This directive appeared in version 1.7.7.

上游包体的持久化

1
2
3
4
5
6
7
8
9
10
11
# 将转发的临时文件做持久化处理
Syntax: proxy_store_access users:permissions ...;
Default:
proxy_store_access user:rw;
Context: http, server, location

# 配置为 on,则将文件改名存储在 root 目录下
Syntax: proxy_store on | off | string;
Default:
proxy_store off;
Context: http, server, location

启用将文件保存到磁盘。on 参数会将文件保存在与指令别名或根路径对应的路径中。off 参数会禁用文件保存功能。此外,可以使用带有变量的字符串来明确设置文件名:

处理上游的响应头部

加工响应内容

当接收到请求,必须经过 HTTP 过滤模块处理,来自上游模块的响应同理。

image-20240324122416413

禁用上游响应头部的功能

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_headers

1
2
3
Syntax:    proxy_ignore_headers field ...;
Default: —
Context: http, server, location
  • 功能:某些响应头部可以改变 Nginx 的行为,使用 proxy_ignore_headers 可以禁止它们生效
  • 可以禁用功能的头部: “X-Accel-Redirect”, “X-Accel-Expires”, “X-Accel-Limit-Rate” (1.1.6), “X-Accel-Buffering” (1.1.6), “X-Accel-Charset” (1.1.6), “Expires”, “Cache-Control”, “Set-Cookie” (0.8.44), and “Vary” (1.7.7).

image-20240324122721081

转发上游的响应

1
2
3
Syntax:    proxy_hide_header field;
Default: —
Context: http, server, location

功能:对上游响应中的某些头部,设置不向客户端转发

默认不转发的响应头部:“Date”, “Server”, “X-Pad”, and “X-Accel-…”

image-20240324123023310

1
2
3
yntax:    proxy_pass_header field;
Default: —
Context: http, server, location

功能:对于已经被 proxy_hide_header 的头部,设置向客户端转发

修改返回的 Set-Cookie 头部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 修改 cookie 中的域名
Syntax: proxy_cookie_domain off;
proxy_cookie_domain domain replacement;
Default:
proxy_cookie_domain off;
Context: http, server, location
This directive appeared in version 1.1.15.

# 修改 cookie 中 url,进行替换
Syntax: proxy_cookie_path off;
proxy_cookie_path path replacement;
Default:
proxy_cookie_path off;
Context: http, server, location
This directive appeared in version 1.1.15.

返回修改的 Location 头部

1
2
3
4
5
6
Syntax:    proxy_redirect default;
proxy_redirect off;
proxy_redirect redirect replacement;
Default:
proxy_redirect default;
Context: http, server, location

替换上游返回的头部中的 Location

上游出现失败时的容错方案

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream

当第一台上游服务器返回错误给 Nginx 时,Nginx 的一些容错方案

1
2
3
4
Syntax:    proxy_next_upstream error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | non_idempotent | off ...;
Default:
proxy_next_upstream error timeout;
Context: http, server, location

前提:没有向客户端发送任何内容,如果向客户端发送字节了,代表这个上游已经生效,此时无法选择新的上游服务

配置:(当上游返回以下情况时)

  • error:例如一些网络错误
  • timeout:请求超时
  • invalid_header:上游返回的 header 不合法
  • http_:具体的响应码
  • non_idempotent:通常,使用非幂等方法(POSTLOCKPATCH)的请求不会被传递到下一个服务器,如果已经向上游服务器发送了请求(1.9.13);显式启用此选项允许重试这些请求;
  • off:关闭将请求传递给下一个上游服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
# 限制请求可以传递到下一个服务器的时间。值为0会关闭此限制。
Syntax: proxy_next_upstream_timeout time;
Default:
proxy_next_upstream_timeout 0;
Context: http, server, location
This directive appeared in version 1.7.5.

# 限制将请求传递给下一个服务器的尝试次数。值为 0 则关闭此限制。
Syntax: proxy_next_upstream_tries number;
Default:
proxy_next_upstream_tries 0;
Context: http, server, location
This directive appeared in version 1.7.5.

用 error_page 拦截上游失败响应

当上游响应的响应码大于等于 300 时,应将响应返回客户端还是按 error_page 指令处理

1
2
3
4
Syntax:    proxy_intercept_errors on | off;
Default:
proxy_intercept_errors off;
Context: http, server, location

对上游服务使用 SSL

双向认证时的指令实例

image-20240324130103836

对下游使用证书

https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate

1
2
3
4
5
6
7
Syntax:    ssl_certificate file;
Default: —
Context: http, server

Syntax: ssl_certificate_key file;
Default: —
Context: http, server

验证下游证书

1
2
3
4
5
6
7
8
Syntax:    ssl_verify_client on | off | optional | optional_no_ca;
Default:
ssl_verify_client off;
Context: http, server

Syntax: ssl_client_certificate file;
Default: —
Context: http, server

对上游使用证书

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_certificate

1
2
3
4
5
6
7
8
9
Syntax:    proxy_ssl_certificate file;
Default: —
Context: http, server, location
This directive appeared in version 1.7.8.

Syntax: proxy_ssl_certificate_key file;
Default: —
Context: http, server, location
This directive appeared in version 1.7.8.

验证上游使用证书

1
2
3
4
5
6
7
8
9
10
Syntax:    proxy_ssl_trusted_certificate file;
Default: —
Context: http, server, location
This directive appeared in version 1.7.0.

Syntax: proxy_ssl_verify on | off;
Default:
proxy_ssl_verify off;
Context: http, server, location
This directive appeared in version 1.7.0.

ssl 模块提供的变量

image-20240324130911904

image-20240324130921799

创建证书的示例

image-20240324130954075

浏览器缓存与 Nginx 缓存

互联网中,使用缓存可以大大提升访问效率。

  • 浏览器缓存
    • 优点
      • 使用有效缓存时,没有网络消耗,速度最快
      • 即使由网络消耗,但对失效缓存使用 304 响应做到网络流量消耗最小化
    • 缺点
      • 仅提升一个用户的体验(也就是用浏览器这一个用户的体验)
  • Nginx 缓存
    • 优点
      • 提升所有用户的体验(作为入口,可以提升所有访问这个入口的用户的体验)
      • 相比浏览器缓存,有效降低上游服务的负载
      • 通过 304 响应减少 Nginx 与上游服务间的流量消耗
    • 缺点
      • 用户仍然保持网络消耗
  • 同时使用浏览器缓存与 Nginx 缓存

浏览器缓存

image-20240324131648320

Etag 头部

image-20240324131748222

https://nginx.org/en/docs/http/ngx_http_core_module.html#etag

1
2
3
4
5
Syntax:    etag on | off;
Default:
etag on;
Context: http, server, location
This directive appeared in version 1.3.3.

启用或禁用静态资源的“ETag”响应头字段的自动生成。(会使用时间的16进制加上返回的字节数)

生成规则

1
ngx_sprintf(etag->value.data, "\"%xT-%xO\"", r->headers_out.last_modified_time,r->headers_out.content_length_n)

If-None-Match

image-20240324131929612

If-Modified-Since 头部

image-20240324131953402

not_modified 过滤模块

功能:用户端拥有缓存,但不确认缓存是否过期,于是在请求中传入 If-Modified-Since 或者 If-None-Match 头部,该模块通过将其值与响应中的 Last-Modified 值相比较,决定是通过 200 返回全部内容,还是仅返回 304 Not Modified 头部,表示浏览器仍然使用之前的缓存。

使用前提:原返回响应码为 200

https://nginx.org/en/docs/http/ngx_http_headers_module.html#expires

1
2
3
4
5
Syntax:    expires [modified] time;
expires epoch | max | off;
Default:
expires off;
Context: http, server, location, if in location

image-20240324132614452

image-20240324132748591

https://nginx.org/en/docs/http/ngx_http_core_module.html#if_modified_since

1
2
3
4
5
Syntax:    if_modified_since off | exact | before;
Default:
if_modified_since exact;
Context: http, server, location
This directive appeared in version 0.7.24.
  • off:忽略请求中的 if_modified_since 头部
  • exact:精确匹配 if_modified_since 头部与 last_modified 的值
  • before:若 if_modified_since 大于等于 last_modified 的值,则返回 304

If-Match

image-20240324133053594

If-Unmodified-Since

image-20240324133112463

Nginx 缓存

定义存放缓存的载体

配置上游服务器响应的缓存

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache

1
2
3
4
5
6
7
8
9
10
11
# 定义共享内存
Syntax: proxy_cache zone | off;
Default:
proxy_cache off;
Context: http, server, location

# 定义共享内存,以及磁盘中文件存放位置
# keys_zone 就是上面定义的共享内存
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

image-20240324133934729

image-20240324133950165

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
proxy_cache_path /data/nginx/cache keys_zone=cache_zone:10m;

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

server {
...
location / {
proxy_pass http://backend;
proxy_cache cache_zone;
proxy_cache_key $uri;
proxy_cache_purge $purge_method;
}
}

缓存的关键字

1
2
3
4
Syntax:    proxy_cache_key string;
Default:
proxy_cache_key $scheme$proxy_host$request_uri;
Context: http, server, location

缓存什么样的响应

1
2
3
Syntax:    proxy_cache_valid [code ...] time;
Default: —
Context: http, server, location
  • 对不同的响应码缓存不等的时长
    • 例如:code 404 5m
  • 只标识时间
    • 进对以下缓存码缓存
      • 200
      • 301
      • 203
  • 通过响应头部控制缓存时长
    • X-Accel-Expires,单位 秒
      • 为 0 时标识禁止 Nginx 缓存内容
      • 通过 @ 设置缓存到一天中的某一时刻
    • 响应头若含有 Set-Cookie 则不缓存
    • 响应头含有 Vary: * 则不缓存

哪些内容不使用缓存

参数为真,响应不存入缓存(例如有些数据存放在 cookie 中)

1
2
3
Syntax:    proxy_no_cache string ...;
Default: —
Context: http, server, location

参数为真,不使用缓存内容(即使响应存入缓存,但是不使用)

1
2
3
Syntax:    proxy_cache_bypass string ...;
Default: —
Context: http, server, location

变更 HEAD 方法

可以将 HEAD 方法变更为 GET 方法

1
2
3
4
5
Syntax:    proxy_cache_convert_head on | off;
Default:
proxy_cache_convert_head on;
Context: http, server, location
This directive appeared in version 1.9.7.

启用或禁用将 HEAD 方法转换为 GET 以进行缓存。当禁用转换时,缓存键应配置为包括 $request_method

upstream_cache_status 变量

标识这个缓存的状态

image-20240324140124381

对客户端请求的缓存处理流程

image-20240324141607692

proxy_cache_methods

https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_methods

1
2
3
4
5
Syntax:    proxy_cache_methods GET | HEAD | POST ...;
Default:
proxy_cache_methods GET HEAD;
Context: http, server, location
This directive appeared in version 0.7.59.

接收上游响应的缓存处理流程

X-Accel-Expires 头部

image-20240324141900121

从上游服务定义缓存多长时间:

  • 0 表示不缓存当前响应
  • @ 前缀标识缓存到当前的某个时间

Vary 头部

image-20240324162037530

Set-Cookie 头部

image-20240324162104669

Set-Cookie 头部没有被 proxy_ignore_headers 设置忽略,则不对响应进行缓存。

image-20240324162200214

减轻缓存失效时上游服务的压力

当缓存大量失效或者重启服务,会导致缓存穿透

第一种方式:合并回源请求(也叫单飞、请求收束)

image-20240324162940560

1
2
3
4
5
Syntax:    proxy_cache_lock on | off;
Default:
proxy_cache_lock off;
Context: http, server, location
This directive appeared in version 1.1.12.

同一时间,仅第一个请求发向上游,其他请求等待第一个响应返回或者超时后,使用缓存响应客户端

1
2
3
4
5
Syntax:    proxy_cache_lock_timeout time;
Default:
proxy_cache_lock_timeout 5s;
Context: http, server, location
This directive appeared in version 1.1.12.

等嗲第一个请求返回响应的最大时间,到达后直接向上游发送请求,但不缓存响应

1
2
3
4
5
Syntax:    proxy_cache_lock_age time;
Default:
proxy_cache_lock_age 5s;
Context: http, server, location
This directive appeared in version 1.7.8.

上一个请求返回响应的超时时间,到达后再放行一个请求发向上游

第二种方式:使用 stale 陈旧的缓存(也称作降级)

image-20240324163300008

1
2
3
4
5
6
7
8
9
10
11
# 配置为 updating 表示使用旧缓存
Syntax: proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;
Default:
proxy_cache_use_stale off;
Context: http, server, location

Syntax: proxy_cache_background_update on | off;
Default:
proxy_cache_background_update off;
Context: http, server, location
This directive appeared in version 1.11.10.

proxy_cache_use_stale 指令:定义陈旧缓存的用法

image-20240324163457533

缓存有问题的响应

1
2
3
4
5
Syntax:    proxy_cache_background_update on | off;
Default:
proxy_cache_background_update off;
Context: http, server, location
This directive appeared in version 1.11.10.

当使用 proxy_cache_use_stale 允许使用过期响应时,将同步生成一个子请求,通过访问上游服务更新过期的缓存

1
2
3
4
5
Syntax:    proxy_cache_revalidate on | off;
Default:
proxy_cache_revalidate off;
Context: http, server, location
This directive appeared in version 1.5.7.

更新缓存时,使用 If-Modified-SinceIf-None-Match 作为请求头部,预期内容未发生变更时,通过 304 来减少传输内容。

这个过程,跟浏览器和 Nginx 交互的流程一样

image-20240324163909591

及时清除缓存

原生缓存会通过定时器决定缓存是否失效,第三方模块提供缓存立即失效的方法

模块:

  • 第三方模块:https://github.com/FRiCKLE/ngx_cache_purge

功能:

  • 接收到指定 HTTP 请求后立刻清除缓存
1
2
3
4
5
6
7
syntax: proxy_cache_purge on|off|<method> [from all|<ip> [.. <ip>]]
default: none
context: http, server, location

syntax: proxy_cache_purge zone_name key
default: none
context: location

其他协议的反向代理

七层反向代理对照:构造请求内容

image-20240324164513109

建立连接并发送请求

image-20240324164607377

接收上游响应

image-20240324164800445

转发响应

image-20240324164820997

SSL

image-20240324164842013

缓存类指令

image-20240324164855206

image-20240324164905322

独有配置

image-20240324164926174

memcached 反向代理

应用级的反向代理

https://nginx.org/en/docs/http/ngx_http_memcached_module.html

功能:

  • 将 HTTP 请求转换为 memcached 协议中的 get 请求,转发请求至上游 memcached 服务
  • get 命令:get <key>*\r\n(协议简单,只能转成 get 请求)
  • 控制命令:<command name> <key> <flags> <exptime> <bytes> [noreply]\r\n
  • 通过设置 memcached_key 变量构造 key

模块默认编译进 Nginx

指令:

image-20240324165308234

websocket 反向代理

https://nginx.org/en/docs/http/websocket.html

让服务器主动向浏览器推送请求

例如:

1
2
3
4
5
6
location /chat/ {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

协议升级

image-20240324165834631

websocket 协议帧

image-20240324165909743

image-20240324165924570

websocket 协议和扩展

image-20240324165940695

用分片提升缓存效率

当上游服务器响应的内容很大,可以通过分片提升缓存效率

https://nginx.org/en/docs/http/ngx_http_slice_module.html

1
2
3
4
Syntax:    slice size;
Default:
slice 0;
Context: http, server, location

功能:通过 range 协议将大文件分解为多个小文件,更好的用缓存为客户端的 range 协议服务

默认没有编译到 Nginx

运行流程:

image-20240324170423433

将文件以分块的形式构建多个请求,将多个请求的分片缓存下来。

1
2
3
4
5
6
7
8
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;
}

通过 open file cache 提升性能

https://nginx.org/en/docs/http/ngx_http_core_module.html#open_file_cache

1
2
3
4
5
Syntax:    open_file_cache off;
open_file_cache max=N [inactive=time];
Default:
open_file_cache off;
Context: http, server, location

缓存哪些元信息

image-20240324170912031

缓存文件句柄,下次使用时,可以不再重新打开文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Syntax:    open_file_cache_errors on | off;
Default:
open_file_cache_errors off;
Context: http, server, location

Syntax: open_file_cache_min_uses number;
Default:
open_file_cache_min_uses 1;
Context: http, server, location

Syntax: open_file_cache_valid time;
Default:
open_file_cache_valid 60s;
Context: http, server, location

HTTP2 协议

主要特性

  • 传输数据量的大幅减少
    • 以二进制方式传输
    • 标头压缩(主要针对 cookie
  • 多路复用及相关功能
    • 消息优先级
  • 服务器消息推送
    • 并行推送

核心概念

image-20240324171405584

  • 连接 Connection:1个 TCP 连接,包含一个或者多个 Stream
  • 数据流 Stream:一个双向通讯数据流,包含多条 Message
  • 消息 Message:对应 HTTP1 中的请求或者响应,包含一条或者多条 Frame
  • 数据帧 Frame:最小单位,以二进制压缩格式存放 HTTP1 中的内容

协议分层

image-20240324171550885

多路复用

image-20240324171621202

传输中无序,接收时组装

image-20240324171657442

数据流优先级

image-20240324171721779

  • 每个数据流有优先级( 1-256)
  • 数据流间可以有依赖关系

标头压缩

image-20240324171806253

Frame 格式

image-20240324171839166

image-20240324171845663

服务器推送 PUSH

image-20240324171910919

http2

https://nginx.org/en/docs/http/ngx_http_v2_module.html

默认没有编译进 Nginx

功能:对客户端使用 http2 协议提供基本可能

前提:开启 TLS/SSL 协议

使用方法:listen 443 ssl http2;

Nginx 推送资源

image-20240324172102999

1
2
3
4
5
6
7
8
9
10
11
12
13
# 例如 如果上游头部添加 Link: style.css,则 Nginx 会将 style.css 文件推送给客户端
Syntax: http2_push_preload on | off;
Default:
http2_push_preload off;
Context: http, server, location
This directive appeared in version 1.13.9.

# 由 Nginx 配置,将对应文件推送给客户端,例如 /image.png
Syntax: http2_push uri | off;
Default:
http2_push off;
Context: http, server, location
This directive appeared in version 1.13.9.

测试 Nginx http2 协议的客户端工具:https://github.com/nghttp2/nghttp2/releases

并发请求控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 最大并行推送数
Syntax: http2_max_concurrent_pushes number;
Default:
http2_max_concurrent_pushes 10;
Context: http, server
This directive appeared in version 1.13.9.

Syntax: http2_max_concurrent_streams number;
Default:
http2_max_concurrent_streams 128;
Context: http, server

Syntax: http2_max_field_size size;
Default:
http2_max_field_size 4k;
Context: http, server

超时控制

1
2
3
4
5
6
7
8
9
Syntax:    http2_recv_timeout time;
Default:
http2_recv_timeout 30s;
Context: http, server

Syntax: http2_idle_timeout time;
Default:
http2_idle_timeout 3m;
Context: http, server

连接最大处理请求数

1
2
3
4
5
6
7
8
9
10
Syntax:    http2_max_requests number;
Default:
http2_max_requests 1000;
Context: http, server
This directive appeared in version 1.11.6.

Syntax: http2_chunk_size size;
Default:
http2_chunk_size 8k;
Context: http, server, location

设置响应包体的分片大小

1
2
3
4
Syntax:    http2_chunk_size size;
Default:
http2_chunk_size 8k;
Context: http, server, location

缓冲区大小设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Syntax:    http2_recv_buffer_size size;
Default:
http2_recv_buffer_size 256k;
Context: http

Syntax: http2_max_header_size size;
Default:
http2_max_header_size 16k;
Context: http, server

Syntax: http2_body_preread_size size;
Default:
http2_body_preread_size 64k;
Context: http, server
This directive appeared in version 1.11.0.

grpc 反向代理

协议:https://grpc.io/

模块:https://nginx.org/en/docs/http/ngx_http_grpc_module.html

默认编译进 Nginx 中,依赖 ngx_http_v2_module 模块

指令对照表

image-20240324172902140

对照 SSL 部分

image-20240324172918894

stream 模块

四层网络功能,相比七层网络而言,四层简单很多。

与七层一样,四层也支持代理,四层网络代理是代理 TCP/UDP 请求。

stream 模块处理请求的 7 个阶段

image-20240325005130744

模块:https://nginx.org/en/docs/stream/ngx_stream_core_module.html

1
2
3
4
5
6
7
8
9
10
11
Syntax:    stream { ... }
Default: —
Context: main

Syntax: server { ... }
Default: —
Context: stream

Syntax: listen address:port [ssl] [udp] [proxy_protocol] [fastopen=number] [backlog=number] [rcvbuf=size] [sndbuf=size] [bind] [ipv6only=on|off] [reuseport] [so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]];
Default: —
Context: server

可以看到,四层反向代理和七层反向代理在配置上的区别是:

四层反向代理的配置在 main 下的 stream 配置块中;

七层反向代理的配置在 main 下的 http 配置块中;

传输层相关的变量

image-20240325005440455

image-20240325005449092

image-20240325005500919

Nginx 系统变量

image-20240325005532502

content 阶段

return 模块

1
2
3
Syntax:    return value;
Default: —
Context: server

proxy_protocol 协议

网络中流量经过网关和防火墙可能会丢失真实的客户端地址,此时需要有额外协议携带真实地址。

image-20240325005932891

v1 协议中,填写的是:源IP 目标IP 源端口 目标端口

读取 proxy_protocol 协议的超时控制

1
2
3
4
5
Syntax:    proxy_protocol_timeout timeout;
Default:
proxy_protocol_timeout 30s;
Context: stream, server
This directive appeared in version 1.11.4.

stream 处理 proxy_protocol 流程

image-20240325010108730

首先查看 Nginx 配置中是否携带 listen proxy_protocol

post_accept 阶段

realip 模块

https://nginx.org/en/docs/stream/ngx_stream_realip_module.html

功能:通过 proxy_protocol 协议获取出客户端真实地址,并写入 remote_addrremote_port 变量。同时使用 realip_remote_addrrealip_remote_port 保留 TCP 连接中获得的原始地址

默认没有编译到 Nginx 中

1
2
3
Syntax:    set_real_ip_from address | CIDR | unix:;
Default: —
Context: stream, server

设置可行地址,从可行地址中读取对端地址。

preaccess 阶段的 limit_conn 模块

https://nginx.org/en/docs/stream/ngx_stream_limit_conn_module.html

功能:限制客户端的并发连接数,使用变量自定义限制依据,基于共享内存所有 worker 进程同时生效。

默认编译进 Nginx

1
2
3
4
5
6
7
8
9
10
11
12
Syntax:    limit_conn_zone key zone=name:size;
Default: —
Context: stream

Syntax: limit_conn zone number;
Default: —
Context: stream, server

Syntax: limit_conn_log_level info | notice | warn | error;
Default:
limit_conn_log_level error;
Context: stream, server

access 阶段的 access 模块

https://nginx.org/en/docs/stream/ngx_stream_access_module.html

根据客户端地址(realip 模块可以修改地址)决定连接的访问权限。

默认编译进 Nginx 模块

1
2
3
4
5
6
7
Syntax:    allow address | CIDR | unix: | all;
Default: —
Context: stream, server

Syntax: deny address | CIDR | unix: | all;
Default: —
Context: stream, server

log 阶段的 stream_log 模块

https://nginx.org/en/docs/stream/ngx_stream_log_module.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Syntax:    access_log path format [buffer=size] [gzip[=level]] [flush=time] [if=condition];
access_log off;
Default:
access_log off;
Context: stream, server

Syntax: log_format name [escape=default|json|none] string ...;
Default: —
Context: stream

Syntax: open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time];
open_log_file_cache off;
Default:
open_log_file_cache off;
Context: stream, server

stream 模块 TLS/SSL 应用场景

image-20240325101549689

绿色代表网络安全的连接。

Nginx 可以单独为客户端和上游服务提供 TLS/SSL 协议,也可以将与客户端之间 TLS/SSL 协议连接转换为到上游的裸 TCP 连接。同样的,也可以将与客户端的 TCP 协议转换为到上游服务的 TLS/SSL 协议。

stream 中的 ssl

https://nginx.org/en/docs/stream/ngx_stream_ssl_module.html

使 stream 反向代理对下游支持 TLS/SSL 协议。

默认不编译进 Nginx

指令对比 HTTP 模块

steam 中的 SSL 与 HTTP 模块中基本一致。

配置基本参数

image-20240325101719100

提升性能

image-20240325101733785

验证客户端证书

image-20240325101748110

ssl 模块提供的变量

image-20240325101814193

image-20240325101825236

可以基于 stream 四层反向代理的 stream_ssl_module 模块解析 TLS 协议

image-20240325101900749

ssl_preread 模块

https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

解析下游 TLS 证书中信息,以变量方式赋能其他模块。

提供变量:

image-20240325102025867

preread 阶段:ssl_preread 模块

https://nginx.org/en/docs/stream/ngx_stream_core_module.html#preread_buffer_size

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Syntax:    preread_buffer_size size;
Default:
preread_buffer_size 16k;
Context: stream, server
This directive appeared in version 1.11.5.

Syntax: preread_timeout timeout;
Default:
preread_timeout 30s;
Context: stream, server
This directive appeared in version 1.11.5.

Syntax: ssl_preread on | off;
Default:
ssl_preread off;
Context: stream, server

image-20240325102618341

通过 ssl_preread 模块,可以获取到下游服务请求的域名,通过域名可以对应代理到不同的上游服务。

反向代理 stream_proxy 模块

https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html

功能:

  • 提供 TCP/UDP 协议的反向代理
  • 支持与上游的连接使用 TLS/SSL 协议
  • 支持与上游的连接使用 proxy protocol 协议

proxy 模块对上下游的限速指令

image-20240325103241309

限制读取上游服务数据的速度

https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_download_rate

1
2
3
4
5
Syntax:    proxy_download_rate rate;
Default:
proxy_download_rate 0;
Context: stream, server
This directive appeared in version 1.9.3.

限制读取客户端数据的速度

1
2
3
4
5
Syntax:    proxy_upload_rate rate;
Default:
proxy_upload_rate 0;
Context: stream, server
This directive appeared in version 1.9.3.

stream 反向代理指令

image-20240325111900834

stream ssl 指令与 http proxy 模块对照

image-20240325112037414

UDP 反向代理

在实时视频会议、音频会议的场景中,使用 UDP 的效果更好。

理论

image-20240325113215179

https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_requests

1
2
3
4
5
Syntax:    proxy_requests number;
Default:
proxy_requests 0;
Context: stream, server
This directive appeared in version 1.15.7.
  • 指定一次会话 session 中最多从客户端接受到多少报文就结束 session
    • 仅会话结束才会记录 access 日志
    • 同一个会话中,Nginx 使用同一端口连接上游服务(也就是上图中的 端口C)
    • 设置为 0 表示不限制,每次请求都会记录 access 地址
1
2
3
4
Syntax:    proxy_responses number;
Default: —
Context: stream, server
This directive appeared in version 1.9.13.
  • 指定对应一个请求报文,上游应返回多少个响应报文(常见的是 1,也就是一个请求一个响应,但是很多时候也不是)
    • proxy_timeout 结合使用,控制上游服务是否不可用

透传 IP 地址

请求通过网络设备后,很多时候可能会丢失原 IP 地址,解决方案有以下几种:

  • proxy_protocol 协议:数据载荷前端带有源IP地址和端口
  • 修改 IP 报文:IP 报文头里面有原始 IP 地址
    • 步骤:
      • 修改 IP 报文中的源地址
      • 修改路由规则
    • 方案:
      • IP 地址透传,经由 Nginx 转发上游返回的报文给客户端(TCP/UDP)
      • DSR:上游直接发送报文给客户端(仅 UDP)

修改源 IP 和路由

image-20240325114736275

操作:

image-20240325114856854

DSR 方案

方案1:修改 TCP 中的源 IP 和源端口,修改路由,返回经由 Nginx 出口

image-20240325115006285

方案二:修改 TCP 中的源 IP 和源端口,在上游服务进程中,修改源地址为网关,可去掉路由。

image-20240325115024477

image-20240325115417485