nginx实现四层的反向代理模块-stream
2019-07-29 12:31:09 阿炯

Nginx 在1.9.0版本以前如果要想做到基于TCP的代理及负载均衡需要通过名为 nginx_tcp_proxy_module 的第三方patch来实现,该模块的代码托管在github上。

Nginx 从1.9.0开始发布ngx_stream_core_module模块,该模块支持tcp代理及负载均衡。ngx_stream_core_module这个模块并不会默认启用,需要在编译时通过指定--with-stream参数来激活这个模块。用来实现四层协议的转发、代理或者负载均衡等。这是要替代HAproxy的节奏,鉴于nginx在7层负载均衡和web service上的成功,以其良好的架构,stream模块前景一片大好。

stream模块必需在nginx.conf中配置

stream模块用法和http模块差不多,关键的是语法近乎一致,熟悉http模块配置语法的上手更快。以下是一个配置了tcp负载均衡和udp(dns)负载均衡的例子,有server,upstream块,而且还有server,hash,listen,proxy_pass等指令。

stream {
upstream mysqld {
hash $remote_addr consistent;
server 192.168.1.42:3306 weight=5 max_fails=3 fail_timeout=10s;#将端口3306反向代理mysqld组的IP:PORT,最大失败次数为3,超时时间为10秒。
server 192.168.1.43:3306 weight=5 max_fails=1 fail_timeout=10s;
}
server {
listen 3306;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass mysqld;
}
}

upstream dns {
server 17.61.29.79:53;
server 17.61.29.80:53;
server 17.61.29.81:53;
server 17.61.29.82:53;
}

server {
listen 127.0.0.1:53 udp;
proxy_responses 1;
proxy_timeout 20s;
proxy_pass dns;
}

#SSH转发
upstream ssh {
    hash $remote_addr consistent;
    server 192.168.0.12:22;
}
server {
listen 2222;
proxy_pass ssh;
}

stream模块的配置里还支持类似server unix:/tmp/backend3.sock;这样的sock数据交换接口,也可以直接proxy_pass unix:/tmp/stream.socket;。
stream {
upstream backend {
hash $remote_addr consistent;
server backend1.freeoa.net:12345 weight=5;
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
server {
listen 12345;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass backend;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}

stream{
upstream emqt_cluster{
    zone tcp_servers 64k;
    hash $remote_addr;
    server 192.168.1.2:1883 max_fails=2 fail_timeout=30s;
    server 192.168.1.3:1883 max_fails=2 fail_timeout=30s;
}
}


ngx_stream_core_module也同样的支持tcp长连接保持。keepidle是保持时间,keepintvl是间隔时间 ,keepcnt是发送的个数。

so_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]


指令

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

设置服务器将接受连接的套接字address和port。可以仅指定端口,地址也可以是主机名,例如:

listen 127.0.0.1:5678;
listen *:5678;
listen 5678;# same as *:5678
listen localhost:5678;

IPv6地址在方括号中指定:
listen [::1]:5678;
listen [::]:5678;

UNIX域套接字使用"unix:"前缀指定:
listen unix:/var/run/nginx.sock;

该ssl参数允许指定此端口上接受的所有连接都应在SSL模式下工作。

该udp参数配置一个侦听套接字以处理数据报(1.9.13)。

的proxy_protocol参数(1.11.4)允许指定这个端口上接受的所有连接应使用 代理服务器协议。

自版本1.13.11起支持PROXY协议版本2。

该listen指令可以有几个特定于与套接字相关的系统调用的附加参数。

backlog=number
设置调用中的backlog参数,该参数 listen()限制挂起连接队列的最大长度(1.9.2)。默认情况下, backlog在FreeBSD,DragonFly BSD和macOS上设置为-1,在其他平台上设置为511。

rcvbuf=size
设置SO_RCVBUF侦听套接字的接收缓冲区大小(选项)(1.11.13)。

sndbuf=size
设置SO_SNDBUF侦听套接字的发送缓冲区大小(选项)(1.11.13)。

bind
此参数指示对bind() 给定地址进行单独调用 address:port。事实是,如果有多个listen指令具有相同的端口但地址不同,并且其中一个 listen指令侦听给定端口(*:port)的所有地址,则nginx将 bind()仅执行*:port。应该注意,getsockname()在这种情况下将进行系统调用以确定接受连接的地址。如果使用ipv6only 或so_keepalive参数,那么对于给定的 address:port对bind()将始终进行单独的调用。

ipv6only= on|off
此参数确定(通过IPV6_V6ONLY套接字选项)侦听通配符地址的IPv6套接字是[::] 仅接受IPv6连接还是仅接受IPv6和IPv4连接。默认情况下,此参数处于启用状态。它只能在开始时设置一次。

reuseport
此参数(1.9.1)指示为每个工作进程创建一个单独的侦听套接字(使用SO_REUSEPORTLinux 3.9+和DragonFly BSD上的套接字选项,或者SO_REUSEPORT_LB在FreeBSD 12+上),允许内核在工作进程之间分配传入连接。目前仅适用于Linux 3.9 +,DragonFly BSD和FreeBSD 12+(1.15.1)。不恰当地使用此选项可能会产生安全 隐患。

so_keepalive= on| off| [ keepidle]:[ keepintvl]:[ keepcnt]
此参数配置侦听套接字的“TCP keepalive”行为。如果省略此参数,则操作系统的设置将对套接字有效。如果将其设置为值“ on”, SO_KEEPALIVE则为套接字打开选项。如果将其设置为值“ off”,SO_KEEPALIVE则为套接字关闭该选项。在每个插槽的基础使用的TCP保活参数某些操作系统支持设置TCP_KEEPIDLE,TCP_KEEPINTVL和TCP_KEEPCNT套接字选项。在这样的系统(目前,Linux的2.4 +,NetBSD的5+和FreeBSD 9.0-STABLE),它们可以使用配置的keepidle,keepintvl和 keepcnt参数。可以省略一个或两个参数,在这种情况下,相应套接字选项的系统默认设置将生效。例如,SO_KEEPALIVE =30m::10将idle timeout(TCP_KEEPIDLE)设置为30分钟,将探测间隔(TCP_KEEPINTVL)保留为系统默认值,并将探测count(TCP_KEEPCNT)设置为10个探测器。

不同的服务器必须监听不同的 address:port对。


语法

SyntaxDefaultContextDescription
preread_buffer_size size16kstream,server指定size了的预读缓冲区。
preread_timeout timeout30sstream,server指定timeout了的预读阶段。
proxy_protocol_timeout timeout30sstream,server指定timeout用于读取PROXY协议标头以完成。如果在此时间内未传输整个标头,则关闭连接。
resolver address ... [valid=time][ipv6=onoff-stream,server 将用于解析上游服务器名称的名称服务器配置到地址中,例如:resolver 127.0.0.1 [:: 1]:5353;
resolver_timeout time30sstream,server设置名称解析的超时
server { ... }-stream设置服务器的配置
stream { ... }-main提供指定流服务器指令的配置文件上下文
tcp_nodelay on | offonstream,server启用或禁用该TCP_NODELAY选项的使用。为客户端和代理服务器连接启用该选项
variables_hash_bucket_size size64stream设置变量哈希表的桶大小,设置哈希表的详细信息在单独的文档中提供 。
variables_hash_max_size size1024stream设置size变量哈希表的最大值,设置哈希表的详细信息在单独的文档中提供。


可以将地址指定为域名或IP地址,以及可选端口。如果未指定端口,则使用端口53。以循环方式查询名称服务器。

默认情况下,nginx将在解析时查找IPv4和IPv6地址。如果不需要查找IPv6地址,则ipv6=off可以指定参数。

默认情况下,nginx使用响应的TTL值缓存答案。可选valid参数允许覆盖它:
resolver 127.0.0.1 [::1]:5353 valid=30s;


stream core 一些嵌入式变量

$binary_remote_addr 二进制格式的客户端地址,值的长度始终为IPv4地址的4个字节或IPv6地址的16个字节
$bytes_received 从客户端接收到的字节数
$bytes_sent 发送到客户端的字节数
$connection 连接序列号
$hostname 连接的主机名
$msec 毫秒精度的当前时间
$nginx_version nginx的版本
$pid worker进程号
$protocol 通信协议(UDP or TCP)
$proxy_protocol_addr 来自PROXY协议头的客户端地址,否则为空字符串(1.11.4)必须先通过proxy_protocol在listen指令中设置参数来启用PROXY协议
$proxy_protocol_port 来自PROXY协议头的客户端端口,否则为空字符串(1.11.4)必须先通过proxy_protocol在listen指令中设置参数来启用PROXY协议
$remote_addr 客户端ip
$remote_port 客户端端口
$server_addr 接受连接的服务器ip,计算此变量需要一次系统调用。所以避免系统调用,在listen指令里必须指定具体的服务器地址并且使用参数bind
$server_port 接受连接的服务器端口
$session_time 毫秒精度的会话时间(版本1.11.4开始)
$status 会话状态(版本1.11.4开始), 可以是一下几个值: 200 成功,400 不能正常解析客户端数据,403 禁止访问,500 服务器内部错误,502 网关错误,比如上游服务器无法连接,503 服务不可用,比如由于限制连接等措施导致
$time_iso8601 ISO 8601时间格式
$time_local 普通日志格式的本地时间戳

注意:变量支持是从 nginx 1.11.2版本开始的。

stream 模块


目前官网上列出的第三方模块、简直就是http模块的镜像、比如access模块访问控制ip和ip段,map模块实现映射、geo模块实现地理位置映射等等。使用这些模块的时候一定要看是哪个版本才支持的、比如log模块,只有在nginx-1.11.4才支持。

ngx_stream_core_module
ngx_stream_access_module
ngx_stream_geo_module
ngx_stream_geoip_module
ngx_stream_js_module
ngx_stream_limit_conn_module
ngx_stream_log_module
ngx_stream_map_module
ngx_stream_proxy_module
ngx_stream_realip_module
ngx_stream_return_module
ngx_stream_split_clients_module
ngx_stream_ssl_module
ngx_stream_ssl_preread_module
ngx_stream_upstream_module
ngx_stream_upstream_hc_module


ngx_stream_core_module

TCP and UDP Load Balancing