1. 引言:为什么需要stream模块?
在当今复杂的网络架构中,应用协议的多样化催生了四层网络代理的需求。nginx最初以http反向代理闻名,但自1.9.0版本起引入的stream模块,使其能力扩展到了tcp/udp层。想象这样一个场景:你需要为mysql集群提供统一的访问入口,或在不同服务器间安全转发ssh连接,甚至为游戏服务器做负载均衡——这些正是stream模块大显身手的领域。
与基于http协议的七层代理不同,stream模块工作在传输层(osi第四层),这意味着它可以处理原始tcp和udp流量,无需理解上层应用协议。这种"协议无关性"带来了极大的灵活性和性能优势。
2. stream与http模块:核心区别解析
2.1 架构层级对比
# http模块(七层代理)示例
http {
upstream backend {
server 10.0.1.2:8080;
server 10.0.1.3:8080;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend;
# 可以读取、修改http头
proxy_set_header x-real-ip $remote_addr;
}
}
}
# stream模块(四层代理)示例
stream {
upstream dbservers {
server 10.0.2.2:3306;
server 10.0.2.3:3306;
}
server {
listen 3306;
proxy_pass dbservers;
# 无法处理http头,只能看到原始tcp流
}
}2.2 功能特性差异
| 特性维度 | http模块 | stream模块 |
|---|---|---|
| 工作层级 | 应用层(第七层) | 传输层(第四层) |
| 协议理解 | 解析http/1.x, http/2, websocket等 | 不解析应用协议,透传原始数据 |
| 处理内容 | 可读取/修改请求头、url、方法等 | 只能看到原始字节流,无法修改内容 |
| 性能开销 | 较高(需要解析协议) | 较低(仅转发数据包) |
| 典型应用 | web服务器、api网关、http负载均衡 | 数据库代理、邮件服务器、游戏服务器、vpn网关 |
| ssl终止 | 支持https解密和重新加密 | 支持ssl透传或终止 |
3. stream模块配置详解
3.1 基础配置结构
# 主配置文件nginx.conf中
# 注意:stream块与http块是平级的,不是嵌套关系
# http模块配置
http {
# ... http相关配置
}
# stream模块配置
stream {
# 共享内存区域,用于工作进程间共享状态
# 对于连接数统计、限流等功能是必须的
shared_stream_zone 10m;
# 上游服务器组定义
upstream backend_tcp {
# 默认轮询负载均衡
server backend1.example.com:12345 weight=3; # 权重3
server backend2.example.com:12345 weight=2; # 权重2
server backup.example.com:12345 backup; # 备份服务器
}
upstream backend_udp {
server udp1.example.com:53;
server udp2.example.com:53;
}
# tcp服务器配置
server {
listen 12345; # 监听tcp端口
# listen 12345 ssl; # 监听ssl/tls
# listen [::1]:12345; # 监听ipv6
proxy_pass backend_tcp; # 转发到上游组
proxy_timeout 30s; # 代理超时时间
proxy_connect_timeout 3s; # 连接上游超时时间
# tcp特定配置
tcp_nodelay on; # 禁用nagle算法
so_keepalive on; # 启用tcp keepalive
}
# udp服务器配置
server {
listen 53 udp; # 监听udp端口
proxy_pass backend_udp;
proxy_timeout 10s;
}
}3.2 核心指令解析
3.2.1 负载均衡策略
stream {
upstream app_servers {
# 1. 轮询(默认)
server 10.0.1.1:9000;
# 2. 加权轮询
server 10.0.1.2:9000 weight=5;
# 3. 最少连接数
least_conn;
server 10.0.1.3:9000;
server 10.0.1.4:9000;
# 4. 哈希(会话保持)
hash $remote_addr consistent;
server 10.0.1.5:9000;
server 10.0.1.6:9000;
# 5. 随机算法
random two;
server 10.0.1.7:9000;
server 10.0.1.8:9000;
# 健康检查(需要nginx-plus或第三方模块)
# health_check interval=10 passes=2 fails=3;
}
server {
listen 9000;
proxy_pass app_servers;
}
}3.2.2 ssl/tls配置
stream {
# ssl上游服务器
upstream ssl_backend {
server 10.0.3.1:443;
}
server {
listen 8443 ssl;
# ssl证书配置
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_protocols tlsv1.2 tlsv1.3;
ssl_ciphers high:!anull:!md5;
# 两种ssl代理模式:
# 模式1:ssl终止(解密流量,看到明文)
proxy_pass ssl_backend;
# 此时与后端的通信可以是明文的
# 模式2:ssl透传(加密直通)
# proxy_ssl on; # 启用ssl连接到上游
# proxy_ssl_certificate /path/to/client.crt;
# proxy_ssl_certificate_key /path/to/client.key;
# proxy_ssl_trusted_certificate /path/to/ca.crt;
# proxy_ssl_verify on; # 验证上游证书
# proxy_ssl_verify_depth 2;
# proxy_ssl_session_reuse on; # ssl会话复用
}
}4. 实战应用场景
4.1 场景一:数据库负载均衡与高可用
# mysql读写分离代理
stream {
upstream mysql_read {
zone mysql_zone 64k; # 共享内存区
least_conn; # 最少连接负载均衡
server db-slave1:3306 weight=3 max_conns=100;
server db-slave2:3306 weight=2 max_conns=100;
server db-slave3:3306 weight=2 max_conns=100;
server db-slave-backup:3306 backup; # 备份节点
}
upstream mysql_write {
server db-master:3306;
}
# 读负载均衡器
server {
listen 3307; # 读端口
# 连接限制
proxy_connect_timeout 1s;
proxy_timeout 3h; # mysql长连接
# 连接数限制(需要limit_conn模块)
limit_conn mysql_conn_zone 200;
limit_conn_log_level error;
proxy_pass mysql_read;
# 错误处理
proxy_next_upstream on;
proxy_next_upstream_timeout 2s;
proxy_next_upstream_tries 2;
}
# 写代理
server {
listen 3308; # 写端口
proxy_pass mysql_write;
}
}4.2 场景二:ssh/sftp跳板机
# ssh安全网关:集中管理服务器访问入口
stream {
# 内部服务器组
upstream ssh_servers {
server 192.168.1.10:22; # web服务器
server 192.168.1.20:22; # 数据库服务器
server 192.168.1.30:22; # 应用服务器
}
server {
listen 2222;
# 访问控制
allow 203.0.113.0/24; # 办公室ip段
allow 192.168.1.100; # 管理员ip
deny all; # 其他全部拒绝
# 连接限制
proxy_connect_timeout 10s;
proxy_timeout 1h;
# 使用客户端真实ip(需要后端ssh配置支持)
proxy_protocol on; # 发送proxy protocol v2
# 日志记录
access_log /var/log/nginx/ssh-access.log;
error_log /var/log/nginx/ssh-error.log;
proxy_pass ssh_servers;
}
}4.3 场景三:游戏服务器代理
# 多区游戏服务器负载均衡
stream {
# 基于地理位置的服务器分配
geo $player_region {
default us_servers;
1.0.0.0/8 cn_servers;
8.0.0.0/8 us_servers;
14.0.0.0/8 au_servers;
46.0.0.0/8 eu_servers;
}
upstream us_servers {
server game-us-east:27015 weight=5;
server game-us-west:27015 weight=5;
}
upstream eu_servers {
server game-eu-frankfurt:27015;
server game-eu-london:27015;
}
upstream cn_servers {
server game-cn-beijing:27015;
server game-cn-shanghai:27015;
}
server {
listen 27015 udp; # 游戏通常使用udp
# udp特定优化
proxy_responses 0; # 不等待响应(适用于单向通信)
proxy_timeout 5s;
# 根据玩家ip选择服务器组
proxy_pass $player_region;
# 缓冲区优化
proxy_buffer_size 16k;
}
}4.4 场景四:dns负载均衡
# dns查询负载均衡
stream {
upstream dns_resolvers {
# 多个上游dns服务器
server 8.8.8.8:53; # google dns
server 1.1.1.1:53; # cloudflare dns
server 208.67.222.222:53; # opendns
}
server {
listen 53 udp reuseport; # reuseport提高udp性能
# udp dns配置
proxy_responses 1; # 等待一个响应
proxy_timeout 2s;
# 响应数据包大小限制
proxy_buffer_size 512;
proxy_pass dns_resolvers;
}
# tcp dns回退(当响应超过512字节时)
server {
listen 53;
proxy_pass dns_resolvers;
}
}5. 高级特性与优化
5.1 连接限流与防护
stream {
# 连接限制区域定义
limit_conn_zone $binary_remote_addr zone=per_ip:10m;
limit_conn_zone $server_name zone=per_server:10m;
# 限速区域
limit_req_zone $binary_remote_addr zone=stream_req:10m rate=10r/s;
server {
listen 5432; # postgresql代理
# 连接数限制
limit_conn per_ip 20; # 每个ip最多20个连接
limit_conn per_server 200; # 本服务最多200个连接
# 连接速率限制
limit_req zone=stream_req burst=20;
# 慢连接防护
proxy_upload_rate 100k; # 上传限速
proxy_download_rate 500k; # 下载限速
proxy_pass postgres_backend;
# 错误页面(简化版)
error_log /var/log/nginx/stream_error.log;
}
}5.2 日志与监控
stream {
log_format stream_basic '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr"';
log_format stream_detailed '$remote_addr - $remote_user [$time_local] '
'"$server_name" $server_port '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" '
'"$upstream_connect_time"';
# 访问日志
access_log /var/log/nginx/stream-access.log stream_basic;
# 如果需要更详细的信息
# access_log /var/log/nginx/stream-access-detailed.log stream_detailed buffer=32k flush=5s;
server {
listen 6379; # redis代理
# 特定服务的日志
access_log /var/log/nginx/redis-access.log stream_basic;
# 实时监控支持
# status_zone redis_service;
proxy_pass redis_backend;
}
}5.3 动态配置与维护
# 使用变量实现动态路由
stream {
# 从外部文件或api获取服务器列表
map $ssl_preread_server_name $backend_name {
mysql.example.com mysql_backend;
pg.example.com postgres_backend;
redis.example.com redis_backend;
default default_backend;
}
upstream mysql_backend {
server 10.0.5.1:3306;
}
upstream postgres_backend {
server 10.0.5.2:5432;
}
server {
listen 443 ssl;
# ssl预读:在握手阶段读取服务器名称
ssl_preread on;
# 根据sni动态选择后端
proxy_pass $backend_name;
# 使用变量控制超时
proxy_timeout $timeout_by_backend;
}
}6. 故障排查与性能调优
6.1 常见问题排查
# 调试配置示例
stream {
server {
listen 3389; # rdp代理
# 详细错误日志
error_log /var/log/nginx/rdp-debug.log debug;
# 调试连接问题
proxy_connect_timeout 5s;
proxy_timeout 30s;
# 缓冲区调试
proxy_buffer_size 4k;
# 临时禁用,用于测试
# deny all;
# return "service in maintenance";
proxy_pass rdp_backend;
# 状态检查端点(需要nginx-plus)
# listen 127.0.0.1:8081;
# status_zone rdp_status;
}
}6.2 性能优化建议
- 内核参数调优:
# 增加最大文件描述符数 sysctl -w fs.file-max=1000000 sysctl -w net.core.somaxconn=65535 # 增加端口范围 sysctl -w net.ipv4.ip_local_port_range="1024 65535"
- nginx配置优化:
# 主配置文件优化
worker_processes auto; # 自动设置工作进程数
worker_rlimit_nofile 100000; # 每个worker的文件描述符限制
events {
worker_connections 65536; # 每个worker的连接数
use epoll; # linux高性能事件模型
multi_accept on;
}
stream {
# 启用端口复用(特别针对udp)
server {
listen 53 udp reuseport;
# ...
}
}7. 总结与最佳实践
7.1 何时使用stream模块
- 适用场景:
- 非http协议的tcp/udp服务代理
- 需要高性能、低延迟的四层负载均衡
- 协议透明转发(不解密、不修改)
- 数据库、游戏、邮件等服务的负载均衡
- 不适用场景:
- 需要修改应用层协议内容
- 基于http头的路由决策
- 需要url重写或重定向
- web应用防火墙功能
7.2 部署建议
- 安全性:
- 结合iptables/firewalld做网络层防护
- 为每个服务使用独立的监听ip或端口
- 实施严格的访问控制列表
- 定期更新ssl证书和密码套件
- 高可用:
- 部署多个nginx实例,使用keepalived实现vip
- 配置健康检查,自动剔除故障后端
- 实现优雅的连接排空和重新加载配置
- 监控:
- 监控连接数、吞吐量、响应时间
- 设置警报阈值
- 保留足够的日志用于审计和故障排查
stream模块的强大之处在于它的简洁性和专注性。它不试图理解它转发的数据,只是高效地移动字节。这种设计哲学使其成为许多场景下的理想解决方案,特别是在微服务架构和混合云环境中。通过合理配置,stream模块可以成为你基础设施中可靠、高效的网络流量调度员。
到此这篇关于nginx stream模块完全指南:四层代理的艺术与实践的文章就介绍到这了,更多相关nginx stream模块内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论