Nginx支持TCP代理和负载均衡-stream模块
ngx_stream_core_module
该ngx_stream_core_module
模块自1.9.0版开始提供。默认情况下不构建此模块,应使用--with-stream
配置参数启用它。
官网:http://nginx.org/en/docs/stream/ngx_stream_core_module.html
示例配置
worker_processes auto; error_log /var/log/nginx/error.log info; #事件 events { worker_connections 1024; } #流模块 stream { #上游后端 upstream backend { hash $remote_addr consistent; server backend1.example.com:12345 weight = 5; server 127.0.0.1:12345 max_fails = 3 fail_timeout = 30s; server unix:/ tmp / backend3; } #上游后端 upstream dns { server 192.168.0.1:53535; server dns.example.com:53; } server { listen 12345; proxy_connect_timeout 1s; proxy_timeout 3s; proxy_pass backend; } server { listen 127.0.0.1:53 udp reuseport; proxy_timeout 20s; proxy_pass dns; } server { listen [::1]:12345; proxy_pass unix:/tmp/stream.socket; } }
指令
`**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:12345; listen *:12345; listen 12345; # same as *:12345 listen localhost:12345;
IPv6地址在方括号中指定:
listen [::1]:12345; listen [::]:12345;
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_REUSEPORT
Linux 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
对。
语法
Syntax | Default | Context | Description | |
---|---|---|---|---|
preread_buffer_size size
|
16k | stream,server | 指定size 了的 预读缓冲区。 |
|
preread_timeout timeout
|
30s | stream,server | 指定timeout 了的 预读阶段。 |
|
proxy_protocol_timeout timeout
|
30s | stream,server | 指定timeout 用于读取PROXY协议标头以完成。如果在此时间内未传输整个标头,则关闭连接。 |
|
resolver address ... [valid =time ][ipv6 =on
|
off |
- | stream,server | 将用于解析上游服务器名称的名称服务器配置到地址中,例如:resolver 127.0.0.1 [:: 1]:5353; |
resolver_timeout time
|
30s | stream,server | 设置名称解析的超时 | |
server { ... } | - | stream | 设置服务器的配置 | |
stream { ... } | - | main | 提供指定流服务器指令的配置文件上下文 | |
tcp_nodelay on | off | on | stream,server | 启用或禁用该TCP_NODELAY 选项的使用。为客户端和代理服务器连接启用该选项 |
|
variables_hash_bucket_size size
|
64 | stream | 设置变量哈希表的桶大小。设置哈希表的详细信息在单独的文档中提供 。 | |
variables_hash_max_size size
|
1024 | stream | 设置size 变量哈希表的最大值。设置哈希表的详细信息在单独的文档中提供。 |
可以将地址指定为域名或IP地址,以及可选端口。如果未指定端口,则使用端口53。以循环方式查询名称服务器。
默认情况下,nginx将在解析时查找IPv4和IPv6地址。如果不需要查找IPv6地址,则ipv6=off
可以指定参数。
默认情况下,nginx使用响应的TTL值缓存答案。可选valid
参数允许覆盖它:
resolver 127.0.0.1 [::1]:5353 valid=30s;
嵌入式变量
该ngx_stream_core_module
模块支持自1.11.2以来的变量。
-
$binary_remote_addr
客户端地址采用二进制形式,值的长度始终为IPv4地址的4个字节或IPv6地址的16个字节
-
$bytes_received
从客户端收到的字节数(1.11.4)
-
$bytes_sent
发送到客户端的字节数
-
$connection
连接序列号
-
$hostname
主机名
-
$msec
以毫秒为单位的当前时间(以毫秒为单位)
-
$nginx_version
nginx版本
-
$pid
工作进程的PID
-
$protocol
用于与客户沟通的协议:
TCP
或UDP
(1.11.4) -
$proxy_protocol_addr
来自PROXY协议头的客户端地址,否则为空字符串(1.11.4)必须先通过
proxy_protocol
在listen指令中设置参数来启用PROXY协议 。 -
$proxy_protocol_port
来自PROXY协议头的客户端端口,否则为空字符串(1.11.4)必须先通过
proxy_protocol
在listen指令中设置参数来启用PROXY协议 。 -
$remote_addr
客户地址
-
$remote_port
客户端端口
-
$server_addr
接受连接的服务器的地址计算此变量的值通常需要一次系统调用。为避免系统调用,listen指令必须指定地址并使用该
bind
参数。 -
$server_port
接受连接的服务器的端口
-
$session_time
会话持续时间(以秒为单位),分辨率为毫秒(1.11.4);
-
$status
会话状态(1.11.4),可以是以下之一:
200
会话成功完成400
无法解析客户端数据,例如PROXY协议头403
例如,当某些客户端地址的访问受限时,禁止访问500
内部服务器错误502
坏网关,例如,如果无法选择或到达上游服务器。503
服务不可用,例如,当访问受连接数限制时 -
$time_iso8601
当地时间采用ISO 8601标准格式
-
$time_local
通用日志格式的本地时间
测试nginx代理TCP协议的配置
realserver : 10.111.17.89:8080
nginx :10.111.16.75
客户端:10.100.34.198
TCP监听端口:2018
配置nginx
nginx1.90对TCP协议的代理并不是默认开启的,需要在编译的时候配置 --with-stream 参数:
./configure --add-module=/root/nginx_upstream_check_module-master --with-stream
make && make install
nginx.config文件参照官网:
stream {
upstream tcpend {
hash $remote_addr consistent;
server 10.111.17.89:8080 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 2018;
proxy_connect_timeout 1s;
proxy_timeout 180s;
proxy_pass tcpend;
}
}
启动nginx,发现nginx已经开始监听2018端口了
cd usr/local/nginx/sbin
#启动
./nginx
#重启
./nginx -s reload
#判断配置文件是否正确
./nginx -t
netstat -anp|grep :2018
[root@vm10-111-16-75 ~]# netstat -anp|grep :2018
tcp 0 0 0.0.0.0:2018 0.0.0.0:* LISTEN 18457/nginx
测试客户端连realserver
在客户端通过telnet连接realserver的2018端口:
telnet
open 10.111.17.89 8080
[root@vm10-65-140-249 ~]# telnet
telnet> open 10.111.17.89 8080
Trying 10.111.17.89...
Connected to 10.111.17.89.
Escape character is '^]'.
Connection closed by foreign host.
[root@vm10-65-140-249 ~]# telnet
telnet> open 10.111.17.89 8080
Trying 10.111.17.89...
Connected to 10.111.17.89.
Escape character is '^]'
在realserver上查看网络连接:
netstat -anpl|grep :8080
[root@vm10-111-17-89 ~]# netstat -anpl|grep :8080
tcp 0 0 :::8080 :::* LISTEN 5182/java
tcp 0 0 ::ffff:10.111.17.89:8080 ::ffff:10.100.34.198:14470 ESTABLISHED 5182/java
可以正常连接
测试客户端连接nginx
在客户端通过telnet连接nginx所在服务器的2018端口
telnet
open 10.111.16.75 2018
[root@vm10-65-140-249 ~]# telnet
telnet> open 10.111.16.75 2018
Trying 10.111.16.75...
Connected to 10.111.16.75.
Escape character is '^]'.
在nginx机器上查看网络连接
[root@vm10-111-16-75 ~]# netstat -anp|grep :2018
tcp 0 0 0.0.0.0:2018 0.0.0.0:* LISTEN 18457/nginx
tcp 0 0 10.111.16.75:2018 10.100.34.198:51539 ESTABLISHED 18458/nginx
在realserver上查看网络连接
[root@vm10-111-17-89 ~]# netstat -anpl|grep :8080
tcp 0 0 :::8080 :::* LISTEN 5182/java
tcp 0 0 ::ffff:10.111.17.89:8080 ::ffff:10.111.16.75:40794 ESTABLISHED 5182/java
可以注意到nginx是给做了一个TCP连接的中转。
client和nginx有一个tcp长连接,nginx和realserver有一个tcp长连接,但是client和realserver之间并没有tcp长连接,仅由nginx服务器负责数据中转。