nginx基于TCP的反向代理

一、4层的负载均衡

  Nginx Plus的商业授权版开始具有TCP负载均衡的功能。从Nginx 1.7.7版本开始加入的,现在变成了一个商业收费版本,想要试用,需要在官网申请。也就是说,Nginx除了以前常用的HTTP负载均衡外,Nginx增加基于TCP协议实现的负载均衡方法。 HTTP负载均衡,也就是我们通常所有“七层负载均衡”,工作在第七层“应用层”。而TCP负载均衡,就是我们通常所说的“四层负载均衡”,工作在“网络层”和“传输层”。例如,LVS(Linux Virtual Server,linux虚拟服务)和F5(一种硬件负载均衡设备),也是属于“四层负载均衡”。

二、nginx的TCP的反向代理

通常我们使用Nginx的upstream做基于http/https端口的7层负载均衡,tcp/udp端口的四层负载均衡一般用LVS或者Haproxy来做。

有两种方式:

1、使用第三方模块nginx_tcp_proxy_module,需要在编译时增加tcp代理模块【nginx_tcp_proxy_module】

2、nginx从1.9.0开始,新增加了一个stream模块,用来实现四层协议的转发、代理或者负载均衡等。这完全就是抢HAproxy份额的节奏,鉴于nginx在7层负载均衡和web service上的成功,和nginx良好的框架,stream模块前景一片光明。

nginx-1.9.0 已发布,该版本增加了 stream 模块用于一般的 TCP 代理和负载均衡。

The ngx_stream_core_module module is available since version 1.9.0. This module is not built by default, it should be enabled with the --with-streamconfiguration parameter.

ngx_stream_core_module 这个模块在1.90版本后将被启用。但是并不会默认安装,需要在编译时通过指定 –with-stream 参数来激活这个模块。

其他改进包括:

  • Change: 删除过时的 aio 和 rtsig 事件处理方法
  • Feature: 可在 upstream 块中使用 “zone” 指令
  • Feature: 流模块,支持 TCP 代理和负载均衡
  • Feature: ngx_http_memcached_module 支持字节范围
  • Feature: Windows 版本支持使用共享内存,带随机化地址空间布局.
  • Feature: “error_log” 指令可在 mail 和 server 级别
  • Bugfix: the “proxy_protocol” parameter of the “listen” directive did not work if not specified in the first “listen” directive for a listen socket.

所以,我们如果需要用到这个功能,就需要加上 –with-stream 参数重新编译nginx。

在了解了实现方法后,再了解下安装方案:

  • 高版本的nginx(1.10以上?)不支持第三方模块nginx_tcp_proxy_module的安装;
  • 高版本的nginx有自带tcp负载均衡配置(stream模块),但是health_check功能只供商业用户使用,第三方tcp心跳检测模块还没有适配上(2018.5);
  • 低版本的nginx可以用第三方模块nginx_tcp_proxy_module实现tcp负载均衡并且支持用check进行心跳检测,打补丁安装第三方模块nginx_tcp_proxy_module来实现tcp负载均衡和心跳检测;

高版本nginx + nginx_tcp_proxy_module(第三方模块不支持) --> 高版本nginx stream(虽然可转发,但health_check暂不可用,未见适配的第三方心跳检测模块) --> 低版本的nginx(安装第三方模块实现tcp负载均衡)。

所以可行的还只有低版本的nginx(安装第三方模块实现tcp负载均衡)。--来源网络未经验证

三、nginx_tcp_proxy_module安装及使用

nginx tcp代理功能由nginx_tcp_proxy_module模块提供,同时监测后端主机状态。该模块包括的模块有: ngx_tcp_module, ngx_tcp_core_module, ngx_tcp_upstream_module, ngx_tcp_proxy_module, ngx_tcp_upstream_ip_hash_module。

3.1、安装步骤:

cd /app
wget http://nginx.org/download/nginx-1.6.3.tar.gz
unzip nginx-1.6.3.tar.gz wget https://github.com/yaoweibin/nginx_tcp_proxy_module/archive/master.zip
unzip master cd /app/nginx-1.6.3
patch -p1 </app/nginx_tcp_proxy_module-master/tcp.patch
./configure --add-module=/app/nginx_tcp_proxy_module-master
make
make install

3.2、nginx.conf文件中配置负载均衡参数

tcp {
upstream server {
server 10.100.138.15:8787;
server 10.100.138.30:8787; #check interval 健康检查时间间隔,单位为毫秒
#rise 检查几次正常后,将server加入以负载列表中
#fall 检查几次失败后,从负载队列移除server
#timeout 检查超时时间,单位为毫秒
check interval=3000 rise=2 fall=5 timeout=1000;
} server {
listen 8787;
proxy_pass server;
so_keepalive on; 
  • tcp_nodelay on;
    }
}

客户端的长连接会断开,没有进展。

TCP负载均衡原理上和LVS等是一致的,工作在更为底层,性能会高于原来HTTP负载均衡不少。但是,不会比LVS更为出色,LVS被置于内核模块,而Nginx工作在用户态,而且,Nginx相对比较重。

四、nginx stream安装及使用

环境:centOS7.3_1611 物理服务器一台

Nginx版本:1.12.1

1.下载NGINX稳定发行版
https://nginx.org/download/nginx-1.12.1.tar.gz

2.解压并切换到安装目录

tar -zxvf nginx-1.12.1.tar.gz
cd nginx-1.12.1

3.编译安装

yum -y install gcc gcc-c++ autoconf automake
yum -y install zlib zlib-devel openssl openssl-devel pcre-devel ./configure --prefix=/opt/nginx --sbin-path=/opt/nginx/sbin/nginx --conf-path=/opt/nginx/conf/nginx.conf --with-http_stub_status_module --with-http_gzip_static_module --with-stream
make
make install
cd /opt/nginx

4.修改配置文件

vim /opt/nginx/conf/nginx.conf(在配置文件最后行添加如下)
stream {
upstream NAME1 {
hash $remote_addr consistent;
server 10.22.0.7:5000 max_fails=3 fail_timeout=30s;
server 10.22.0.8:5000 max_fails=3 fail_timeout=30s;
}
upstream NAME2 {
hash $remote_addr consistent;
server 192.168.5.8:8080 max_fails=3 fail_timeout=30s;
}
server{
listen 8080;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass NAME1;
}
server{
listen 60000;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass NAME2;
}
}
解析:

如上配置文件的含义为
将端口8080反向代理NAME1组的serverIP:PORT,最大失败次数为3,超时时间为30秒;
将端口60000反向代理NAME2组的serverIP:PORT,最大失败次数为3,超时时间为30秒。

5.检测语法

/opt/nginx/sbin/nginx -t

6.开启NGINX

/opt/nginx/sbin/nginx

7.重启NGINX

/opt/nginx/sbin/nginx -s reload

这里推荐使用reload而不是restart。

8.访问IP:PORT验证是否生效

stream core 一些变量
(注意:变量支持是从 nginx 1.11.2版本开始的)
$binary_remote_addr
二进制格式的客户端地址
$bytes_received
从客户端接收到的字节数
$bytes_sent
发往客户端的字节数
$hostname
连接域名
$msec
毫秒精度的当前时间
$nginx_version
nginx 版本
$pid
worker进程号
$protocol
通信协议(UDP or TCP)
$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
普通日志格式的时间戳

五、TCP负载均衡的执行原理

当Nginx从监听端口收到一个新的客户端链接时,立刻执行路由调度算法,获得指定需要连接的服务IP,然后创建一个新的上游连接,连接到指定服务器。

nginx基于TCP的反向代理

TCP负载均衡支持Nginx原有的调度算法,包括Round Robin(默认,轮询调度),哈希(选择一致)等。同时,调度信息数据也会和健壮性检测模块一起协作,为每个连接选择适当的目标上游服务器。如果使用Hash负载均衡的调度方法,你可以使用$remote_addr(客户端IP)来达成简单持久化会话(同一个客户端IP的连接,总是落到同一个服务server上)。

和其他upstream模块一样,TCP的stream模块也支持自定义负载均和的转发权重(配置“weight=2”),还有backup和down的参数,用于踢掉失效的上游服务器。max_conns参数可以限制一台服务器的TCP连接数量,根据服务器的容量来设置恰当的配置数值,尤其在高并发的场景下,可以达到过载保护的目的。

Nginx监控客户端连接和上游连接,一旦接收到数据,则Nginx会立刻读取并且推送到上游连接,不会做TCP连接内的数据检测。Nginx维护一份内存缓冲区,用于客户端和上游数据的写入。如果客户端或者服务端传输了量很大的数据,缓冲区会适当增加内存的大小。

nginx基于TCP的反向代理

当Nginx收到任意一方的关闭连接通知,或者TCP连接被闲置超过了proxy_timeout配置的时间,连接将会被关闭。对于TCP长连接,我们更应该选择适当的proxy_timeout的时间,同时,关注监听socke的so_keepalive参数,防止过早地断开连接。

服务健壮性监控

TCP负载均衡模块支持内置健壮性检测,一台上游服务器如果拒绝TCP连接超过proxy_connect_timeout配置的时间,将会被认为已经失效。在这种情况下,Nginx立刻尝试连接upstream组内的另一台正常的服务器。连接失败信息将会记录到Nginx的错误日志中。

nginx基于TCP的反向代理

如果一台服务器,反复失败(超过了max_fails或者fail_timeout配置的参数),Nginx也会踢掉这台服务器。服务器被踢掉60秒后,Nginx会偶尔尝试重连它,检测它是否恢复正常。如果服务器恢复正常,Nginx将它加回到upstream组内,缓慢加大连接请求的比例。

之所“缓慢加大”,因为通常一个服务都有“热点数据”,也就是说,80%以上甚至更多的请求,实际都会被阻挡在“热点数据缓存”中,真正执行处理的请求只有很少的一部分。在机器刚刚启动的时候,“热点数据缓存”实际上还没有建立,这个时候爆发性地转发大量请求过来,很可能导致机器无法“承受”而再次挂掉。以MySQL为例子,我们的mysql查询,通常95%以上都是落在了内存cache中,真正执行查询的并不多。

其实,无论是单台机器或者一个集群,在高并发请求场景下,重启或者切换,都存在这个风险,解决的途径主要是两种:

(1)请求逐步增加,从少到多,逐步积累热点数据,最终达到正常服务状态。
(2)提前准备好“常用”的数据,主动对服务做“预热”,预热完成之后,再开放服务器的访问。

TCP负载均衡原理上和LVS等是一致的,工作在更为底层,性能会高于原来HTTP负载均衡不少。但是,不会比LVS更为出色,LVS被置于内核模块,而Nginx工作在用户态,而且,Nginx相对比较重。

上一篇:使用Nginx反向代理和内容替换模块实现网页内容动态替换功能


下一篇:declare-styleable:自定义控件的属性