nginx––– tcp and udp 代理Introductionnginx 反向代理一般都是7层代理,进行http/https 协议层的转发;说起4层代理,一般想到的都是lvs 和 haproxy 这些;目前nginx新版本已经支持 4层 (tcp,udp) 代理; 在Nginx1.9.0版本之前,TCP代理一般会使用Haproxy或Nginx的第三方包nginx_tcp_proxy_module。但Nginx在1.9.0版本之后加入了ngx_stream_proxy_modulea,它提供了TCP代理,只需在编译Nginx时加入––ngx_stream_proxy_module即可。 在1.9.13版本之后,Nginx加入了对UDP(UserDatagramProtocol)代理的支持,因此可以使用Nginx来代理DNS的UDP端口; Install[root@network-test nginx-1.19.2]# ./configure --help # --with-stream 开启tcp/udp 代理;一般是初次安装的时候使用; # --with-stream=dynamic 动态开启tcp/udp;存量已安装的nginx 下动态支持 # 这次使用动态升级的方法,在原始参数后面添加 –with-stream=dynamic ./configure --prefix=/usr/local/nginx --add-module=../ngx_devel_kit --add-module=../set-misc-nginx-module --with-stream=dynamic # make编译 ,切记不要install,执行install 会有覆盖的情况,可能会影响存量的业务或配置,需要注意 make # 当前目录objs中会存在 编译好的 ngx_stream_module.so ll objs/ngx_stream_module.so # 将对于文件cp 到 存量已安装的目录 mkdir /usr/local/nginx/modules cp objs/ngx_stream_module.so /usr/local/nginx/modules/ # 编辑 nginx.conf ; reload 或 重启服务 # load_module modules/ngx_stream_module.so; [root@network-test nginx]# head -n 30 conf/nginx.conf | grep -v '^$' load_module modules/ngx_stream_module.so; #user nobody; worker_processes 1; error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } stream { upstream tcp_backed { hash $remote_addr consistent; server 127.0.0.1:9090 weight=4 max_fails=3 fail_timeout=30s; } server { listen 9999; proxy_connect_timeout 1s; proxy_timeout 3s; proxy_pass tcp_backed; } }

 


 Configuring TCP OR UDP Load BalancingTCP代理在stream指令块内进行声明,位于main内,和http指令块同级。 反向代理的upstream支持DNS域名(如ip_hash、socket)配置、权重即故障转移(如max_fails)配置。 当proxy_pass代理TCP时,没有http://前缀,注意配置时不要写错。 支持和HTTP一样的连接超时参数proxy_timeout、proxy_connect_timeout。
在实操这里时,需要提到一点是,一般4层代理是没有转发日志的;比如lvs ;nginx 这里使用tcp/udp 代理时是可以配置转发日志的; 配置方法: 在nginx.conf stream 中配置对应log_farmart; stream {
log_format tcp_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 logs/tcp-access.log tcp_proxy ; open_log_file_cache off; #include /etc/nginx/conf.d/*.stream;
upstream tcp_backed { hash $remote_addr consistent; server 127.0.0.1:9090 weight=4 max_fails=3 fail_timeout=30s; } # proxy_bind $remote_addr transparent; server { listen 9999; proxy_connect_timeout 1s; proxy_timeout 3s; proxy_pass tcp_backed; } }
配置经验 - 测试发现nginx会等待session结束才会记录到日志文件;
- session日志只是tcp层面的记录,包括session时间,发送接收字节数等等;
- session内部发送日志(比如一个socket连接建立起来以后,多次发送心跳数据)需要在应用层面才能记录;
常见指令: TCP代理还包含其他很多指令,下面将介绍一些常用的指令。 指令:proxy_bind 语法:proxy_bind address [transparent] | off; 默认值:无 环境:stream、server 含义:如果此配置为off,则表示请求将会使用系统自动分配的本地IP地址,即后端服务看不到用户的真实IP地址; 如果配置为“proxy_bind $remote_addr transparent;”,则后端服务可以看到用户的真实IP地址。
为了使参数生效,需要以超级用户权限运行Nginx的worker进程,并配置核心路由表以截获反向代理服务器的网络流量。 查看nginx upstream 服务的业务日志,在proxy_bind address off 的配置下,upstream 服务日志显示为 nginx 本地ip: 直接配置该参数后,抓包看的话,是可以看到向RS 转发的ip 从 nginx 本身的ip 变成了 client 真实ip; 不过在开启时,可能出现后端RS 无法正常响应的情况;需要以超级用户权限运行Nginx的worker进程,并配置核心路由表以截获反向代理服务器的网络流量。 代理服务器上需要配置iptables 以及对应路由表信息;上游服务器也要指向对应的网关; 这部分的配置,也找到了一些文档;不过部署的测试环境,一直没调通 o(╥﹏╥)o ;所以这部分暂时不细写;
 指令:proxy_download_rate 语法:proxy_download_rate rate; 默认值:proxy_download_rate 0; 环境:stream、server 含义:设置后端服务器读取数据的速度。速度定义为字节每秒。 默认值为0,表示禁用限速。 限速设置的值对每个连接都有效。
指令:proxy_next_upstream 语法:proxy_next_upstream on | off; 默认值:proxy_next_upstream on; 环境:stream、server 含义:当无法与当前的后端服务器建立连接时,该指令用来确定是否将客户端连接传递给下一台后端服务器。这可能会受到尝试次数(proxy_next_upstream_tries)和时间(proxy_next_upstream_timeout)的影响。
指令:proxy_next_upstream_timeout 语法:proxy_next_upstream_timeout time; 默认值:proxy_next_upstream_timeout 0; 环境:stream、server 含义:设置传递连接到下一台后端服务器的时间。默认值为0,表示关闭这个限制。
指令:proxy_next_upstream_tries 语法:proxy_next_upstream_tries number; 默认值:proxy_next_upstream_tries 0; 环境:stream、server 含义:设置传递连接到下一台后端服务器的尝试次数。默认值为0,表示关闭这个限制。
指令:proxy_pass 语法:proxy_pass address; 默认值:无 环境:server 含义:设置被代理的服务器地址。地址可以是一个域名,也可以是IP地址加端口号。从Nginx1.11.3版本开始支持配置变量,如“proxy_pass $upstream;”。
指令:resolver 语法:resolver address ... [valid=time] [ipv6=on|off]; 环境:stream、server含义:在进行DNS解析时,该指令用于对upstream中出现的域名进行IP地址解析,然后将请求代理到解析到的IP地址上; Valid=time表示DNS解析后的缓存时间,使用缓存时间可以减少DNS解析的次数; 关于ipv6=on|off,如果设置为on,则表示在查询IPv4(Internet Protocol version 4,互联网协议版本4)无果后会继续查询IPv6(Internet Protocol Version 6,互联网协议版本6),如果不需要查找IPv6,可以配置为off,以缩短查找时间。
指令:resolver_timeout 语法:resolver_timeout time; 默认值:resolver_timeout 30s; 执行阶段:stream、server 含义:设置解析DNS的超时时间,如果超时,DNS会使用上一次解析到的IP地址。
指令:proxy_protocol_timeout 语法:proxy_protocol_timeout timeout; 默认值:proxy_protocol_timeout 30s; 环境:stream、server 含义:设置读取proxy协议头的时间。如果在所设置的时间内没有发送完整的报头,则关闭连接。
实战经验 1.指令nginx_tcp_proxy_module和ngx_stream_core_module都可以在TCP代理中使用。其中ngx_stream_core_module包含有关日志记录的一些常用变量,通过这些日志信息可以分析每个TCP请求的情况。 2.在做TCP代理时,Nginx代理节点服务器可能不止一台,可以使用DNS轮询或LVS(LinuxVirtualServer,Linux虚拟服务器)等功能对Nginx进行负载均衡。 3.Redis属于单核服务,所以在一台服务器上启动多个Redis实例是很正常的。如果多个Redis从库部署在同一台服务器上,可以通过TCP代理进行转发,否则会因为端口不一致,导致配置非常烦琐。
引用资料相关nginx 官网链接和参考资料: https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/ http://nginx.org/en/docs/stream/stream_processing.html http://nginx.org/en/docs/stream/ngx_stream_log_module.html#open_log_file_cache http://nginx.org/en/docs/stream/ngx_stream_core_module.html http://nginx.org/en/docs/varindex.html http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind https://github.com/vislee/leevis.com/issues/142 http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_bind https://www.nginx.com/blog/ip-transparency-direct-server-return-nginx-plus-transparent-proxy/ https://pengpengxp.github.io/archive/before-2018-11-10/2017-06-27-%E4%BD%BF%E7%94%A8nginx%E7%9A%84proxy_bind%E9%80%89%E9%A1%B9%E9%85%8D%E7%BD%AE%E9%80%8F%E6%98%8E%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86.html#tproxy_sum |