- 自 version 1.9.0 以来新增了 ngx_stream_core_module 模块,使 nginx 支持四层负载均衡。这个模块不仅能实现 TCP 和 UDP 转发,还能支持负载均衡 upstream 配置。默认编译的时候该模块并未编译进去,需要编译的时候添加 --with-stream 参数使其支持 stream 代理。
- 由于协议的不同,UDP 转发仅会将请求包转发至目标,UDP 回复包将由目标机器直接发出给你的请求端。这个回复包是不会经过转发端的,所以在你转发目标端 IP 已经被不明设备给屏蔽无法连接的话,这个 UDP 回复包你还是收不到,这并不是 Nginx 的问题。
- 请注意,stream 配置不能放到 http 内,因为stream是通过tcp层转发,而不是 http 转发
使用Nginx实现TCP反向代理
- 下图是 nginx upstream keepalive 长连接的实现原理。首先每个进程需要一个 connection pool,里面都是长连接,多进程之间是不需要共享这个连接池的。 一旦与后端服务器建立连接,则在当前请求连接结束之后不会立即关闭连接,而是把用完的连接保存在一个 keepalive connection pool 里面,以后每次需要建立向后连接的时候,只需要从这个连接池里面找。
- 如果找到合适的连接的话,就可以直接来用这个连接,不需要重新创建 socket 或者发起 connect()。这样既省下建立连接时在握手的时间消耗,又可以避免 TCP 连接的 slow start 慢启动。如果在 keepalive 连接池找不到合适的连接,那就按照原来的步骤重新建立连接。
- 如果你的连接池的数控制在 128 个,总共线程池内的线程数是 128 * nginx worker 个,但因为你要应对更多的并发请求,所以临时又加了很多的连接,但这临时的连接是短连接和长连接要看你的 Nginx 版本。那他如何被收回,两地保证,一点是他会主动去释放,另一点是 keepalive timeout 的时间。
使用Nginx实现TCP反向代理
1. 手动编译
需要注意的是,使用 DockerHub 中的 Nginx 镜像是不用二次编译的。
# 下载1.9版本以上的nginx wget http://nginx.org/download/nginx-1.20.2.tar.gz # 安装依赖包 yum install -y gcc glibc gcc-c++ prce-devel openssl-devel pcre-devel useradd -s /sbin/nologin nginx -M # 加压目录 tar xf nginx-1.10.3.tar.gz && cd nginx-1.20.2 # 手动编译 ./configure \ --prefix=/usr/local/nginx-1.20.2 \ --user=nginx \ --group=nginx \ --with-http_ssl_module \ --with-http_stub_status_module \ --with-stream # 安装到系统上 make && make install # 检查配置文件 /usr/local/nginx/sbin/nginx -t
2. Nginx TCP 转发
以下的配置就是 TCP 转发的最简配置
- 我们能很明显的发现,stream 模块的配置其实跟 http 模块很类似。但实际上 stream 模块与 http 模块上完全是两套不同的处理流程。用最简单的说法就是,http 模块是基于 Layer7 层的应用层处理流程,而 Stream 仅在 Layer4 层上对连接进行处理。
- 所以 stream 模块无法像 http 模块那样能区分 vhost 主机名,然而这在 stream 模块在引入了 ssl 配置之后又能支持了。而且 stream 模块还能引入 ssl/tls 来对 TCP 连接进行加密。由于 TLS 标准内对 SNI 提供了支持,所以又能识别主机名了。在理论上,stream 模块的端口转发效率实际上相比 http 模块的反向代理效率更高。
user nginx; worker_processes 1; events { worker_connections 1024; } stream { # 全局配置 preread_timeout 120s; proxy_connect_timeout 120s; proxy_protocol_timeout 120s; resolver_timeout 120s; proxy_timeout 120s; tcp_nodelay on; # 设置日志格式 log_format proxy '$remote_addr [$time_local] ' '$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 proxy; error_log /var/log/nginx/stream.error.log error; upstream app_pg { hash $remote_addr consistent; server 192.168.100.60:5432; server 192.168.100.61:5432; server 192.168.100.62:5432; } server { # 不指定协议默认是TCP协议 listen 127.0.0.1:5432 so_keepalive=on; proxy_pass app_pg; } server{ # keepalive的可配置参数差不多有以下几个:keepidle,keepintvl,keepcnt # keepidle为连接保持时间;keepintvl为连接的间隔时间;keepcnt是连接的个数 # 下示将idle超时设置为30分钟,探测间隔为系统默认值,并将探测计数设置为10个探测器 # 实际配置的格式为:so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt] listen *:3306 so_keepalive=30m::10; proxy_connect_timeout 10s; proxy_timeout 20s; proxy_buffer_size 512k; proxy_pass 192.168.100.60:8000; } }
- Nginx实现 SSH 转发
user nginx; worker_processes 1; events { worker_connections 1024; } stream { upstream ssh { hash $remote_addr consistent; server 192.168.1.42:22 weight=5; } server { listen 2222; proxy_pass ssh; } }
3. Nginx UDP 转发
以下的配置就是 UDP 转发的最简配置
- UDP 转发并不是 stream 模块一开始就支持的,而是在 1.9.3 版本之后的 stream 模块才追加了 UDP 转发支持,所以要配置 UDP 转发前必须得先确定自己的 Nginx 版本是否达到了要求。
user nginx; worker_processes 1; events { worker_connections 1024; } stream { # 全局配置 proxy_timeout 120s; tcp_nodelay on; # 设置日志格式 log_format proxy '$remote_addr [$time_local] ' '$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 proxy; error_log /var/log/nginx/stream.error.log error; # 配置dns负载均衡 upstream dns_upstreams { server 1.1.1.1:53 weight=1; server 1.0.0.1:53 weight=1; # weight负载均衡权重 server 8.8.8.8:53 weight=1 backup; # backup标记为备用服务器 } server{ listen 53 udp; proxy_responses 1; # UDP协议专用;期望后端返回给客户端数据包的数量 proxy_timeout 20s; # 超时时间 proxy_pass dns_upstreams; } }
分享笔记