- 04: 新增 random 负载均衡、upstream 响应时间变量详解 - 10: 新增访问控制、连接限制、地理/真实IP模块、高级日志配置 - 24: 新增 worker_aio_requests、EPOLLEXCLUSIVE 详解 - 30: njs JavaScript 模块完整指南 - 31: OpenTelemetry 可观测性集成指南 - 32: ACME 自动证书管理指南 Co-Authored-By: Claude <noreply@anthropic.com>
1062 lines
22 KiB
Markdown
1062 lines
22 KiB
Markdown
# NGINX TCP/UDP Stream 模块指南
|
||
|
||
## 1. Stream 模块概述
|
||
|
||
Stream 模块提供 TCP/UDP 流处理功能,包括:
|
||
- TCP 代理与负载均衡
|
||
- UDP 代理(DNS、日志收集等)
|
||
- TLS/SSL 终端
|
||
- 基于 SNI 的路由
|
||
|
||
### 版本要求
|
||
|
||
- 自 1.9.0 版本可用
|
||
- 默认不构建,需编译时添加 `--with-stream` 参数
|
||
|
||
### 配置上下文
|
||
|
||
```nginx
|
||
stream {
|
||
# TCP/UDP 配置
|
||
server {
|
||
listen 12345;
|
||
proxy_pass backend:54321;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 基础配置示例
|
||
|
||
### TCP 代理
|
||
|
||
```nginx
|
||
stream {
|
||
upstream backend {
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
}
|
||
|
||
server {
|
||
listen 3306;
|
||
proxy_pass backend;
|
||
proxy_timeout 3s;
|
||
proxy_connect_timeout 1s;
|
||
}
|
||
}
|
||
```
|
||
|
||
### UDP 代理
|
||
|
||
```nginx
|
||
stream {
|
||
upstream dns_servers {
|
||
server 8.8.8.8:53;
|
||
server 8.8.4.4:53;
|
||
}
|
||
|
||
server {
|
||
listen 53 udp;
|
||
proxy_pass dns_servers;
|
||
proxy_timeout 20s;
|
||
}
|
||
}
|
||
```
|
||
|
||
### Unix Socket 代理
|
||
|
||
```nginx
|
||
stream {
|
||
server {
|
||
listen unix:/tmp/stream.sock;
|
||
proxy_pass unix:/tmp/backend.sock;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 负载均衡
|
||
|
||
### 配置示例
|
||
|
||
```nginx
|
||
stream {
|
||
upstream mysql_backend {
|
||
hash $remote_addr consistent; # 一致性哈希
|
||
server mysql1:3306 weight=5;
|
||
server mysql2:3306;
|
||
server mysql3:3306 backup;
|
||
}
|
||
|
||
server {
|
||
listen 3306;
|
||
proxy_pass mysql_backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 负载均衡算法
|
||
|
||
| 算法 | 指令 | 说明 |
|
||
|------|------|------|
|
||
| 轮询 | 默认 | 加权轮询 |
|
||
| 最少连接 | `least_conn;` | 连接数最少优先 |
|
||
| 哈希 | `hash key [consistent];` | 基于键哈希 |
|
||
| 最少时间 | `least_time header \| last_byte \| last_byte inflight;` | 最小响应时间(NGINX Plus) |
|
||
| 随机 | `random [two] [least_conn];` | 随机选择 |
|
||
|
||
### server 参数
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `weight=N` | 权重 |
|
||
| `max_conns=N` | 最大连接数 |
|
||
| `max_fails=N` | 失败次数阈值 |
|
||
| `fail_timeout=T` | 失败统计时间 |
|
||
| `backup` | 备份服务器 |
|
||
| `down` | 标记不可用 |
|
||
| `resolve` | 解析域名 IP 变化 |
|
||
|
||
### 新负载均衡算法
|
||
|
||
#### least_time(最小响应时间)
|
||
|
||
**版本要求**:NGINX Plus
|
||
|
||
```nginx
|
||
upstream mysql_backend {
|
||
least_time header; # 或 last_byte, last_byte inflight
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
zone mysql 64k;
|
||
}
|
||
```
|
||
|
||
**参数说明**:
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `header` | 以接收到上游第一个字节的时间为度量 |
|
||
| `last_byte` | 以接收到上游完整响应的时间为度量 |
|
||
| `last_byte inflight` | 考虑正在传输的数据 |
|
||
|
||
#### random(随机选择)
|
||
|
||
```nginx
|
||
upstream backend {
|
||
random; # 纯随机
|
||
# random two; # 随机选两个,按权重选
|
||
# random two least_conn; # 随机选两个,选连接少的
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
}
|
||
```
|
||
|
||
**参数说明**:
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `two` | 随机选择两个上游服务器,再根据负载均衡策略选择 |
|
||
| `least_conn` | 与 `two` 配合,选择连接数较少的 |
|
||
|
||
### upstream zone 共享内存
|
||
|
||
`zone` 指令启用 upstream 配置的共享内存,多 worker 进程间共享连接状态:
|
||
|
||
```nginx
|
||
upstream backend {
|
||
zone backend 64k; # 64k 共享内存
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
keepalive 32;
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- 共享内存使所有 worker 进程共享 upstream 状态
|
||
- 必需用于 `least_conn`、`least_time`、健康检查等
|
||
- 大小根据上游服务器数量调整
|
||
|
||
|
||
---
|
||
|
||
## 4. 核心指令
|
||
|
||
### listen 指令
|
||
|
||
```nginx
|
||
server {
|
||
listen 80; # TCP
|
||
listen 53 udp; # UDP
|
||
listen 443 ssl; # TLS
|
||
listen 12345 udp reuseport; # UDP + reuseport
|
||
listen [::]:80; # IPv6
|
||
listen unix:/tmp/stream.sock; # Unix Socket
|
||
}
|
||
```
|
||
|
||
**参数说明**:
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `ssl` | 启用 SSL |
|
||
| `udp` | UDP 协议 |
|
||
| `reuseport` | 每个 worker 独立监听 |
|
||
| `proxy_protocol` | 启用 PROXY 协议 |
|
||
| `backlog=N` | 连接队列长度 |
|
||
| `so_keepalive` | TCP keepalive |
|
||
| `transparent` | 启用透明代理 |
|
||
|
||
### proxy_pass 指令
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_pass 192.168.1.1:3306;
|
||
proxy_pass backend;
|
||
proxy_pass $upstream;
|
||
}
|
||
```
|
||
|
||
### 超时配置
|
||
|
||
```nginx
|
||
server {
|
||
proxy_timeout 10m; # 客户端/后端之间读写超时(默认 10m)
|
||
proxy_connect_timeout 60s; # 连接后端超时(默认 60s)
|
||
}
|
||
```
|
||
|
||
### 缓冲配置
|
||
|
||
```nginx
|
||
server {
|
||
proxy_buffer_size 16k; # 读写缓冲区大小(默认 16k)
|
||
}
|
||
```
|
||
|
||
### 其他核心指令
|
||
|
||
| 指令 | 语法 | 默认值 | 上下文 | 说明 |
|
||
|------|------|--------|--------|------|
|
||
| `proxy_bind` | `proxy_bind address [transparent];` | — | stream, server | 指定代理连接使用的本地地址 |
|
||
| `proxy_half_close` | `proxy_half_close on \| off;` | off | stream, server | 启用 TCP 半关闭支持 |
|
||
| `proxy_responses` | `proxy_responses number;` | — | stream, server (UDP) | UDP 每请求期望响应数 |
|
||
| `proxy_socket_keepalive` | `proxy_socket_keepalive on \| off;` | off | stream, server | 开启与上游的 TCP keepalive |
|
||
|
||
**示例配置**:
|
||
|
||
```nginx
|
||
# 透明代理
|
||
server {
|
||
listen 3306 transparent;
|
||
proxy_bind $remote_addr transparent;
|
||
proxy_pass backend:3306;
|
||
}
|
||
|
||
# UDP 配置
|
||
server {
|
||
listen 53 udp;
|
||
proxy_pass dns_backend:53;
|
||
proxy_responses 1; # 每请求期望1个响应
|
||
}
|
||
|
||
# 半关闭支持(TCP 流式场景)
|
||
server {
|
||
listen 9000;
|
||
proxy_half_close on;
|
||
proxy_pass backend:9000;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. SSL/TLS 配置
|
||
|
||
### 服务端 SSL
|
||
|
||
```nginx
|
||
stream {
|
||
server {
|
||
listen 443 ssl;
|
||
ssl_certificate /path/to/cert.pem;
|
||
ssl_certificate_key /path/to/key.pem;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
|
||
proxy_pass backend:8080;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 上游 SSL(连接后端使用 SSL)
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_pass backend:3306;
|
||
|
||
proxy_ssl on;
|
||
proxy_ssl_protocols TLSv1.2 TLSv1.3;
|
||
proxy_ssl_verify on;
|
||
proxy_ssl_trusted_certificate /path/to/ca.pem;
|
||
proxy_ssl_server_name on;
|
||
}
|
||
```
|
||
|
||
### SSL 配置指令
|
||
|
||
| 指令 | 说明 |
|
||
|------|------|
|
||
| `ssl_certificate` | 证书文件 |
|
||
| `ssl_certificate_key` | 私钥文件 |
|
||
| `ssl_protocols` | 启用的协议 |
|
||
| `ssl_ciphers` | 加密套件 |
|
||
| `ssl_session_cache` | 会话缓存 |
|
||
| `proxy_ssl` | 启用上游 SSL |
|
||
| `proxy_ssl_verify` | 验证上游证书 |
|
||
| `proxy_ssl_server_name` | 启用 SNI |
|
||
|
||
#### 完整上游 SSL 配置示例
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_pass ssl_backend:3306;
|
||
|
||
proxy_ssl on;
|
||
proxy_ssl_protocols TLSv1.2 TLSv1.3;
|
||
proxy_ssl_ciphers HIGH:!aNULL;
|
||
proxy_ssl_certificate /path/to/client.crt;
|
||
proxy_ssl_certificate_key /path/to/client.key;
|
||
proxy_ssl_verify on;
|
||
proxy_ssl_trusted_certificate /path/to/ca.crt;
|
||
proxy_ssl_verify_depth 2;
|
||
proxy_ssl_name backend.example.com;
|
||
proxy_ssl_session_reuse on;
|
||
}
|
||
```
|
||
|
||
**指令说明**:
|
||
|
||
| 指令 | 说明 |
|
||
|------|------|
|
||
| `proxy_ssl_certificate` | 客户端证书(mTLS) |
|
||
| `proxy_ssl_certificate_key` | 客户端证书私钥 |
|
||
| `proxy_ssl_ciphers` | 加密套件 |
|
||
| `proxy_ssl_verify_depth` | 证书链验证深度 |
|
||
| `proxy_ssl_name` | 验证上游证书的域名 |
|
||
| `proxy_ssl_session_reuse` | 启用 SSL 会话复用 |
|
||
|
||
---
|
||
|
||
## 6. 基于名称的虚拟服务器(SNI)
|
||
|
||
**版本要求**:1.25.5+
|
||
|
||
```nginx
|
||
stream {
|
||
map $ssl_server_name $backend {
|
||
app1.example.com app1_backend;
|
||
app2.example.com app2_backend;
|
||
default default_backend;
|
||
}
|
||
|
||
upstream app1_backend {
|
||
server 192.168.1.1:8080;
|
||
}
|
||
|
||
upstream app2_backend {
|
||
server 192.168.1.2:8080;
|
||
}
|
||
|
||
server {
|
||
listen 443 ssl;
|
||
server_name app1.example.com app2.example.com;
|
||
|
||
ssl_certificate /path/to/cert.pem;
|
||
ssl_certificate_key /path/to/key.pem;
|
||
|
||
proxy_pass $backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
### SSL Preread SNI 路由(无需终止 SSL)
|
||
|
||
**版本要求**:1.25.5+
|
||
|
||
使用 `ssl_preread` 模块在不解密的情况下读取 SNI 信息进行路由:
|
||
|
||
```nginx
|
||
stream {
|
||
ssl_preread on; # 启用 ssl_preread
|
||
|
||
map $ssl_preread_server_name $backend {
|
||
mysql.example.com mysql_backend;
|
||
redis.example.com redis_backend;
|
||
default default_backend;
|
||
}
|
||
|
||
upstream mysql_backend {
|
||
server 192.168.1.1:3306;
|
||
}
|
||
|
||
upstream redis_backend {
|
||
server 192.168.1.2:6379;
|
||
}
|
||
|
||
upstream default_backend {
|
||
server 192.168.1.3:8080;
|
||
}
|
||
|
||
server {
|
||
listen 443;
|
||
ssl_preread on; # 在 server 上下文启用
|
||
proxy_pass $backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- `ssl_preread` 读取 ClientHello 中的 SNI 扩展
|
||
- 无需配置 SSL 证书即可实现基于域名的路由
|
||
- 适用于多服务共享端口的场景
|
||
|
||
---
|
||
|
||
## 7. PROXY 协议
|
||
|
||
### 接收 PROXY 协议
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306 proxy_protocol;
|
||
proxy_pass backend:3306;
|
||
}
|
||
```
|
||
|
||
### 发送 PROXY 协议
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_protocol on;
|
||
proxy_pass backend:3306;
|
||
}
|
||
```
|
||
|
||
### PROXY 协议变量
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `$proxy_protocol_addr` | 客户端 IP |
|
||
| `$proxy_protocol_port` | 客户端端口 |
|
||
| `$proxy_protocol_server_addr` | 服务器 IP |
|
||
| `$proxy_protocol_server_port` | 服务器端口 |
|
||
|
||
---
|
||
|
||
## 8. 速率限制
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_pass backend:3306;
|
||
|
||
proxy_download_rate 1m; # 限制从后端读取速率(字节/秒)
|
||
proxy_upload_rate 1m; # 限制从客户端读取速率(字节/秒)
|
||
}
|
||
```
|
||
|
||
**使用变量动态限制**:
|
||
```nginx
|
||
map $remote_addr $limit_rate {
|
||
default 1m;
|
||
10.0.0.1 10m; # 特定 IP 更高速率
|
||
}
|
||
|
||
server {
|
||
proxy_download_rate $limit_rate;
|
||
proxy_upload_rate $limit_rate;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 故障转移
|
||
|
||
```nginx
|
||
server {
|
||
listen 3306;
|
||
proxy_pass backend:3306;
|
||
|
||
proxy_next_upstream on; # 连接失败时尝试下一台
|
||
proxy_next_upstream_timeout 30s; # 总时间限制
|
||
proxy_next_upstream_tries 3; # 尝试次数限制
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 连接保持
|
||
|
||
### keepalive 连接池配置
|
||
|
||
```nginx
|
||
upstream backend {
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
|
||
keepalive 32; # 空闲连接池大小
|
||
keepalive_requests 100; # 单连接最大请求(HTTP 适用)
|
||
keepalive_timeout 60s; # 空闲超时
|
||
}
|
||
```
|
||
|
||
**指令说明**:
|
||
|
||
| 指令 | 语法 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `keepalive` | `keepalive connections;` | — | 保持到上游的空闲连接数 |
|
||
| `keepalive_requests` | `keepalive_requests number;` | 100 | 单连接最大请求数 |
|
||
| `keepalive_timeout` | `keepalive_timeout timeout;` | 60s | 空闲连接超时时间 |
|
||
|
||
---
|
||
|
||
## 11. 内置变量
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `$remote_addr` | 客户端 IP |
|
||
| `$remote_port` | 客户端端口 |
|
||
| `$server_addr` | 服务器 IP |
|
||
| `$server_port` | 服务器端口 |
|
||
| `$protocol` | 协议(TCP/UDP) |
|
||
| `$bytes_received` | 接收字节数 |
|
||
| `$bytes_sent` | 发送字节数 |
|
||
| `$session_time` | 会话时间(秒) |
|
||
| `$status` | 会话状态 |
|
||
| `$ssl_preread_server_name` | SNI 名称 |
|
||
|
||
### 其他 stream 指令
|
||
|
||
| 指令 | 语法 | 默认值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `preread_buffer_size` | `preread_buffer_size size;` | 16k | 预读缓冲区大小 |
|
||
| `preread_timeout` | `preread_timeout timeout;` | 30s | 预读超时时间 |
|
||
| `resolver` | `resolver address ... [valid=time];` | — | DNS 解析器 |
|
||
| `resolver_timeout` | `resolver_timeout time;` | 30s | 解析超时 |
|
||
| `tcp_nodelay` | `tcp_nodelay on \| off;` | on | 启用 TCP_NODELAY |
|
||
| `variables_hash_max_size` | `variables_hash_max_size size;` | 1024 | 变量哈希表最大大小 |
|
||
| `variables_hash_bucket_size` | `variables_hash_bucket_size size;` | 64 | 变量哈希表桶大小 |
|
||
|
||
---
|
||
|
||
## 12. 应用场景示例
|
||
|
||
### MySQL 代理
|
||
|
||
```nginx
|
||
stream {
|
||
upstream mysql_servers {
|
||
least_conn;
|
||
server mysql1:3306 weight=5;
|
||
server mysql2:3306;
|
||
server mysql3:3306 backup;
|
||
}
|
||
|
||
server {
|
||
listen 3306;
|
||
proxy_pass mysql_servers;
|
||
proxy_timeout 600s;
|
||
proxy_connect_timeout 2s;
|
||
}
|
||
}
|
||
```
|
||
|
||
### Redis 代理
|
||
|
||
```nginx
|
||
stream {
|
||
upstream redis_servers {
|
||
server redis1:6379;
|
||
server redis2:6379;
|
||
}
|
||
|
||
server {
|
||
listen 6379;
|
||
proxy_pass redis_servers;
|
||
proxy_timeout 300s;
|
||
}
|
||
}
|
||
```
|
||
|
||
### DNS 代理
|
||
|
||
```nginx
|
||
stream {
|
||
upstream dns_servers {
|
||
server 8.8.8.8:53;
|
||
server 8.8.4.4:53;
|
||
}
|
||
|
||
server {
|
||
listen 53 udp reuseport;
|
||
proxy_pass dns_servers;
|
||
proxy_timeout 20s;
|
||
proxy_responses 1; # 期望 1 个响应
|
||
}
|
||
}
|
||
```
|
||
|
||
### 日志收集(Syslog)
|
||
|
||
```nginx
|
||
stream {
|
||
upstream syslog_servers {
|
||
server syslog1:514;
|
||
server syslog2:514;
|
||
}
|
||
|
||
server {
|
||
listen 514 udp;
|
||
proxy_pass syslog_servers;
|
||
proxy_timeout 10s;
|
||
}
|
||
}
|
||
```
|
||
|
||
### WebSocket 代理(TCP 层)
|
||
|
||
```nginx
|
||
stream {
|
||
upstream websocket_servers {
|
||
server ws1:8080;
|
||
server ws2:8080;
|
||
}
|
||
|
||
server {
|
||
listen 8080;
|
||
proxy_pass websocket_servers;
|
||
proxy_timeout 3600s; # 长连接超时
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 日志配置
|
||
|
||
```nginx
|
||
stream {
|
||
log_format main '$remote_addr [$time_local] '
|
||
'$protocol $status $bytes_sent $bytes_received '
|
||
'$session_time "$upstream_addr"';
|
||
|
||
access_log /var/log/nginx/stream.log main;
|
||
|
||
server {
|
||
listen 3306;
|
||
proxy_pass backend:3306;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 14. 健康检查
|
||
|
||
### 被动检查(内置)
|
||
|
||
```nginx
|
||
upstream backend {
|
||
server 192.168.1.1:3306 max_fails=3 fail_timeout=30s;
|
||
server 192.168.1.2:3306 max_fails=3 fail_timeout=30s;
|
||
}
|
||
```
|
||
|
||
### 主动检查(NGINX Plus)
|
||
|
||
```nginx
|
||
upstream backend {
|
||
zone backend 64k;
|
||
|
||
server 192.168.1.1:3306;
|
||
server 192.168.1.2:3306;
|
||
|
||
health_check interval=5s passes=2 fails=3;
|
||
health_check_timeout 5s;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 15. 访问控制模块
|
||
|
||
### ngx_stream_access_module
|
||
|
||
基于 IP 地址的访问控制,允许或拒绝特定客户端连接。
|
||
|
||
**指令**:
|
||
|
||
| 指令 | 语法 | 默认值 | 上下文 |
|
||
|------|------|--------|--------|
|
||
| `allow` | `allow address \| CIDR \| unix: \| all;` | — | stream, server |
|
||
| `deny` | `deny address \| CIDR \| unix: \| all;` | — | stream, server |
|
||
|
||
**配置示例**:
|
||
|
||
```nginx
|
||
stream {
|
||
# 数据库访问控制
|
||
server {
|
||
listen 3306;
|
||
|
||
# 允许内网访问
|
||
allow 10.0.0.0/8;
|
||
allow 192.168.0.0/16;
|
||
allow 172.16.0.0/12;
|
||
|
||
# 拒绝其他所有
|
||
deny all;
|
||
|
||
proxy_pass mysql_backend;
|
||
}
|
||
|
||
# Redis 访问控制
|
||
server {
|
||
listen 6379;
|
||
|
||
# 仅允许特定 IP
|
||
allow 192.168.1.100;
|
||
allow 192.168.1.101;
|
||
deny all;
|
||
|
||
proxy_pass redis_backend;
|
||
}
|
||
|
||
# 管理端口(仅本地)
|
||
server {
|
||
listen 9000;
|
||
|
||
allow 127.0.0.1;
|
||
deny all;
|
||
|
||
proxy_pass admin_backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**规则匹配顺序**:
|
||
- 按配置顺序依次检查
|
||
- 首个匹配的规则决定结果
|
||
- 未匹配任何规则时默认允许
|
||
|
||
---
|
||
|
||
## 16. 连接限制模块
|
||
|
||
### ngx_stream_limit_conn_module
|
||
|
||
限制并发连接数,防止资源耗尽。
|
||
|
||
**指令**:
|
||
|
||
| 指令 | 语法 | 默认值 | 上下文 |
|
||
|------|------|--------|--------|
|
||
| `limit_conn_zone` | `limit_conn_zone key zone=name:size;` | — | stream |
|
||
| `limit_conn` | `limit_conn zone number;` | — | stream, server |
|
||
| `limit_conn_log_level` | `limit_conn_log_level info \| notice \| warn \| error;` | error | stream, server |
|
||
|
||
**配置示例**:
|
||
|
||
```nginx
|
||
stream {
|
||
# 按客户端 IP 限制连接数
|
||
limit_conn_zone $binary_remote_addr zone=addr:10m;
|
||
|
||
# 按上游服务器限制连接数
|
||
limit_conn_zone $server_addr zone=server:10m;
|
||
|
||
# MySQL 代理 - 每 IP 最多 10 个连接
|
||
server {
|
||
listen 3306;
|
||
limit_conn addr 10;
|
||
proxy_pass mysql_backend;
|
||
}
|
||
|
||
# Redis 代理 - 每 IP 最多 5 个连接
|
||
server {
|
||
listen 6379;
|
||
limit_conn addr 5;
|
||
limit_conn_log_level warn;
|
||
proxy_pass redis_backend;
|
||
}
|
||
|
||
# 全局连接限制
|
||
server {
|
||
listen 8080;
|
||
limit_conn addr 50; # 每 IP 最多 50
|
||
limit_conn server 1000; # 服务总连接上限
|
||
proxy_pass backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**内存计算**:
|
||
- 1MB 共享内存可存储约 16,000 个 32 字节 key($binary_remote_addr)
|
||
- 或约 8,000 个 IPv6 地址(16 字节)
|
||
|
||
---
|
||
|
||
## 17. 地理位置模块
|
||
|
||
### ngx_stream_geo_module
|
||
|
||
根据客户端 IP 地址创建变量值,用于地理路由或访问控制。
|
||
|
||
**指令**:
|
||
|
||
| 指令 | 语法 | 默认值 | 上下文 |
|
||
|------|------|--------|--------|
|
||
| `geo` | `geo [$address] $variable { ... }` | — | stream |
|
||
|
||
**配置示例**:
|
||
|
||
```nginx
|
||
stream {
|
||
# 基础地理映射
|
||
geo $remote_addr $region {
|
||
default other;
|
||
10.0.0.0/8 internal;
|
||
192.168.0.0/16 internal;
|
||
172.16.0.0/12 internal;
|
||
|
||
# 中国大陆 IP 段(示例)
|
||
1.0.1.0/24 china;
|
||
1.0.2.0/23 china;
|
||
# ... 更多 IP 段
|
||
}
|
||
|
||
# 使用变量进行路由
|
||
map $region $backend_pool {
|
||
internal internal_backend;
|
||
china china_backend;
|
||
other global_backend;
|
||
}
|
||
|
||
upstream internal_backend {
|
||
server 192.168.1.1:3306;
|
||
}
|
||
|
||
upstream china_backend {
|
||
server 10.0.1.1:3306;
|
||
}
|
||
|
||
upstream global_backend {
|
||
server 10.0.2.1:3306;
|
||
}
|
||
|
||
server {
|
||
listen 3306;
|
||
proxy_pass $backend_pool;
|
||
}
|
||
}
|
||
```
|
||
|
||
**高级用法**:
|
||
|
||
```nginx
|
||
stream {
|
||
# 使用变量作为地址源
|
||
geo $realip_remote_addr $region {
|
||
default other;
|
||
# ... 配置
|
||
}
|
||
|
||
# 带 CIDR 包含
|
||
geo $country {
|
||
default XX;
|
||
include /etc/nginx/geo/countries.conf;
|
||
}
|
||
|
||
# countries.conf 内容示例:
|
||
# 1.0.1.0/24 CN;
|
||
# 1.0.2.0/23 CN;
|
||
# 1.1.1.0/24 AU;
|
||
}
|
||
|
||
# 使用 GeoIP 数据库(需 ngx_stream_geoip_module)
|
||
geoip_country /usr/share/GeoIP/GeoIP.dat;
|
||
|
||
map $geoip_country_code $backend {
|
||
default global_backend;
|
||
CN china_backend;
|
||
US us_backend;
|
||
EU eu_backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 18. 真实 IP 模块
|
||
|
||
### ngx_stream_realip_module
|
||
|
||
处理 PROXY 协议头,获取客户端真实 IP 地址。
|
||
|
||
**指令**:
|
||
|
||
| 指令 | 语法 | 默认值 | 上下文 |
|
||
|------|------|--------|--------|
|
||
| `set_real_ip_from` | `set_real_ip_from address \| CIDR;` | — | stream, server |
|
||
| `real_ip_header` | `real_ip_header field;` | proxy_protocol | stream, server |
|
||
|
||
**配置示例**:
|
||
|
||
```nginx
|
||
stream {
|
||
server {
|
||
listen 3306 proxy_protocol; # 接收 PROXY 协议
|
||
|
||
# 信任的代理服务器地址
|
||
set_real_ip_from 10.0.0.0/8;
|
||
set_real_ip_from 192.168.0.0/16;
|
||
set_real_ip_from 172.16.0.0/12;
|
||
|
||
proxy_pass mysql_backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**可用变量**:
|
||
|
||
| 变量 | 说明 |
|
||
|------|------|
|
||
| `$realip_remote_addr` | 原始客户端地址(PROXY 协议中的地址)|
|
||
| `$realip_remote_port` | 原始客户端端口 |
|
||
| `$proxy_protocol_addr` | PROXY 协议中的客户端地址 |
|
||
| `$proxy_protocol_port` | PROXY 协议中的客户端端口 |
|
||
| `$proxy_protocol_server_addr` | PROXY 协议中的目标服务器地址 |
|
||
| `$proxy_protocol_server_port` | PROXY 协议中的目标服务器端口 |
|
||
|
||
**典型场景**:
|
||
|
||
```nginx
|
||
stream {
|
||
# 场景:负载均衡器 → NGINX → 后端
|
||
server {
|
||
listen 3306 proxy_protocol;
|
||
|
||
# 负载均衡器的 IP
|
||
set_real_ip_from 10.0.0.1;
|
||
set_real_ip_from 10.0.0.2;
|
||
|
||
# 使用真实 IP 进行限流
|
||
limit_conn_zone $realip_remote_addr zone=conn_limit:10m;
|
||
limit_conn conn_limit 10;
|
||
|
||
# 日志记录真实 IP
|
||
log_format main '$realip_remote_addr [$time_local] '
|
||
'$protocol $status $bytes_sent $bytes_received';
|
||
access_log /var/log/nginx/stream.log main;
|
||
|
||
proxy_pass mysql_backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 19. 高级日志配置
|
||
|
||
### 日志格式详解
|
||
|
||
```nginx
|
||
stream {
|
||
# JSON 格式日志
|
||
log_format json_combined escape=json
|
||
'{'
|
||
'"time_local":"$time_local",'
|
||
'"remote_addr":"$remote_addr",'
|
||
'"server_addr":"$server_addr",'
|
||
'"server_port":"$server_port",'
|
||
'"protocol":"$protocol",'
|
||
'"status":"$status",'
|
||
'"bytes_sent":"$bytes_sent",'
|
||
'"bytes_received":"$bytes_received",'
|
||
'"session_time":"$session_time",'
|
||
'"upstream_addr":"$upstream_addr",'
|
||
'"upstream_bytes_sent":"$upstream_bytes_sent",'
|
||
'"upstream_bytes_received":"$upstream_bytes_received",'
|
||
'"upstream_connect_time":"$upstream_connect_time"'
|
||
'}';
|
||
|
||
# 详细格式日志
|
||
log_format detailed '$remote_addr - [$time_local] '
|
||
'$protocol/$status '
|
||
'sent:$bytes_sent recv:$bytes_received '
|
||
'time:$session_time '
|
||
'upstream:$upstream_addr '
|
||
'upstream_time:$upstream_connect_time';
|
||
|
||
# 条件日志(仅记录错误)
|
||
map $status $loggable {
|
||
~^[23] 0;
|
||
default 1;
|
||
}
|
||
|
||
server {
|
||
listen 3306;
|
||
access_log /var/log/nginx/stream.json json_combined;
|
||
access_log /var/log/nginx/stream_errors.log detailed if=$loggable;
|
||
proxy_pass backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 日志缓冲与压缩
|
||
|
||
```nginx
|
||
stream {
|
||
server {
|
||
listen 3306;
|
||
|
||
# 缓冲写入(提升性能)
|
||
access_log /var/log/nginx/stream.log main buffer=32k flush=5s;
|
||
|
||
# gzip 压缩日志
|
||
access_log /var/log/nginx/stream.log.gz main gzip buffer=32k;
|
||
|
||
proxy_pass backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
### open_log_file_cache
|
||
|
||
缓存日志文件描述符,减少文件打开操作:
|
||
|
||
```nginx
|
||
stream {
|
||
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
|
||
|
||
server {
|
||
listen 3306;
|
||
access_log /var/log/nginx/stream.log main;
|
||
proxy_pass backend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**参数说明**:
|
||
|
||
| 参数 | 说明 |
|
||
|------|------|
|
||
| `max` | 缓存的最大文件描述符数 |
|
||
| `inactive` | 非活动文件保留时间 |
|
||
| `valid` | 检查文件是否有效的时间间隔 |
|
||
| `min_uses` | 最小使用次数才缓存 | |