nginx代理高级应用

运维军团祝你元宵节快乐

小序:先感谢军粉们的支持,新的一年运维军团依然秉持给大家分享原创干货的宗旨。春节假期后的首篇文章,希望大家能够喜欢。

本期文章介绍nginx代理实践与应用

1 Nginx代理功能介绍

日常业务中经常会遇到各种代理转发的需求。其中,有些应用本身提供代理程序,如zabbix 的zabbix-proxy。有些应用有第三方解决方案,如saltstack的salt-broker。但也有许多应用不提供类似的代理方案,这时就需要专门的代理程序。 

常用的通用代理方案有iptables、haproxy。而Nginx自1.9.0起加入stream模块并支持TCP转发,自1.9.13起 stream模块也开始支持udp,由此也成为了通用代理的一个优秀可选方案。下面是几个方案的功能比较:

HTTP应用层

TCP/UDP层

多个上层源负载均衡

上层源健康检查

Nginx

支持

支持

支持

商业版支持

社区版需要第三方模块

iptables

不支持

支持

不支持

不支持

haproxy

支持

不支持UDP

支持

支持

可以看到,Nginx基本能覆盖日常全方面的代理需求。而且,Nginx的转发配置也与HTTP的虚拟主机类似,配置和维护都比较简单。

2 Nginx反向代理实现tcp中转

我国因为各地网络状况不一样,服务器一般采用bgp机房网络是比较理想的。但假如一个旧业务所在机房的连通性不佳时怎么办呢,考虑迁移机房是一个办法,但是其实也可以用 nginx 的反向代理实现 bgp 中转的效果。

比如手游客户端,可以在客户端增加检测逻辑,当游戏客户端直接访问游戏服务端(tcp连接)出现网络波动时,把访问切到用于tcp转发的bgp IP,尽量规避卡顿,提升游戏体验。如果是游戏连接用的是udp,也可以采用类似的做法。

以下是tcp类型的nginx配置:

tcp {    upstream gamex_android_cn_s1001 {        server 10.*.*.17:10001;    }    server {        listen 33001;        proxy_pass gamex_android_cn_s1001;    }    access_log /data/logs/proxy/tcp/gamex_android_cn_s1001.log; }

3 Nginx反向代理实现web中转

http也是tcp的一种,不过nginx提供了更灵活的http转发方案,下面贴个精简版配置做参考,介绍下web服务example.3xx.com针对小运营商的中转方案。

假设源服务器A是在华南地区电信/联通双线机房(假设电信IP为1.2.3.32,联通IP为2.3.4.33)。下面选择一台在北京bgp机房的机器B(假设IP为3.4.5.6),作为各种业务中转专用机器。机器B上面部署了nginx服务,然后配置example.3xx.com的反向代理:

upstream example_xxx {        server 1.2.3.32:80 ;        server 2.3.4.33:80 backup ; } server {        listen       80;        server_name example.xxx.com;        proxy_connect_timeout 2;        proxy_read_timeout 10;        location / {                proxy_next_upstream http_502 http_504 error timeout invalid_header;                proxy_pass  ;                proxy_redirect     off;                proxy_set_header   Host             $host;                proxy_set_header   X-Real-IP        $remote_addr;                proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;                access_log  /data/logs/$host.proxy.log  access;        } }

然后在dnspod上把各种小运营商和教育网都配置解析到上面服务器ip上。

当然这里的一个前提是,bgp机房的中转机器X到源服务器网络是比较稳定的。而因为源服务器有两条线路,Nginx反向代理可以实现线路择优,因此总体还是比较稳定的。土豪的话,还可以拉个专线。

4 关于web中转后获取玩家实际IP的问题

加上bgp中转后,存在一个问题,源服务器上nginx服务日志获取到的remote IP变成了中转机器X的IP,会影响玩家来源数据的准确性。

这里有两个解决方案,一个是在业务代码层做修改,判断remote IP为3.4.5.6的时候,就取real IP作为玩家IP。

另一个运维层做解决。下面介绍nginx的一个编译参数,可以直接获取中转前的访问IP:--with-http_realip_module

重新编译nginx后,修改下配置,实现如果remote IP为X,把real IP填到remote IP的位置。

#BGP转发时,获取玩家访问ipset_real_ip_from   3.4.5.6;#real_ip_header     X-Forwarded-For;real_ip_header     X-Real-IP; real_ip_recursive  on;

这样运维把问题解决好,免去了找业务开发童鞋改代码的麻烦。

5 利用Nginx反向代理优化服务器访问的方案

现在,example.3xx.com至少有两个可用的服务器,南方机房源服务器A和北方机房转发机B。那如果另一个业务机器P需要访问example.3xx.com的接口,实际访问到的是服务器A还是服务器B呢?默认情况下只能交给DNS解析了,或者在hosts绑定一个相对稳定的IP。

假如访问的是机器A的电信IP,某一天机器P到机器A电信IP的中间路由刚好出故障。运维在收到告警后,就得上机器P手工改hosts切换到机器A的联通IP或者转发机器B;故障恢复后再手工切回A。考虑到国内网络的复杂性,这种问题出现的可能性并不低。

针对这种多节点提供服务的情况,我们希望能实时检测节点的健康状态。当某节点服务不可用,自动剔除该节点,只请求到可用节点上;节点重新恢复时,检测成功后,重新加回可用节点,接受请求;最终提高P访问X业务的成功率。而这里,Nginx反向代理又能派上用场了!

我们在机器P上利用nginx的upstream进行多节点自动选择转发。nginx社区版中,上层源的max_fails和fail_timeout功能较弱,但nginx只在商业版提供health_check健康检查功能。最后我们使用了nginx第三方的模块nginx_upstream_check_module实现相同功能(注意,该模块目前只支持HTTP应用层的健康检查)。tengine也有类似功能,但线上配置改动成本大,这里不做讨论。

下面的例子中,我们搭建了一个测试环境:

业务机器C(10.*.*.32)和D(10.*.*.33),均是ceshi.3xx.com的业务节点;

业务机器Q(10.*.*.101)需要访问ceshi.3xx.com;

目的是在机器C和D至少有一个可用的情况下,仍能保证机器Q正常访问ceshi.3xx.com。

5.1 机器环境及安装、配置

在Q机上,部署nginx 转发健康检查功能的机器环境:

操作系统

CentOS 6 x64

nginx版本

1.8.1

nginx

编译参数

--user=www --group=www --prefix=/usr/local/nginx   --with-http_stub_status_module --with-google_perftools_module   --with-http_ssl_module --add-module=../nginx_upstream_check_module-master

5.1.1 安装带nginx_upstream_check_module的nginx

#下载nginxwget http://nginx.org/download/nginx-1.8.1.tar.gz#下载nginx_upstream_check_module模块wget tar xvf nginx-1.8.1.tar.gz unzip master.zip#打补丁,编译安装cd nginx-1.8.1patch -p1 < ../nginx_http_upstream_check_module/check_1.7.2+.patch ./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-google_perftools_module --with-http_ssl_module --add-module=../nginx_upstream_check_module-master make make install

5.1.2 nginx配置反向代理

ceshi.3xx.com.proxy.conf

upstream w3xxx {                                #主节点C                server 10.*.*.32:80 ;                                #备用节点D                server 10.*.*.33:80  backup;                                                #nginx_upstream_check_module功能配置:                check interval=5000 rise=2 fall=2 timeout=3000;                #说明:                #interval 5秒对各个节点做一次80端口探测                #rise     2次成功,节点可用,则  接受正式请求                #fall     2次失败,节点剔除,则不接受正式请求                #timeout  1次探测的网络连接超时时间} server {        listen       80;        server_name ceshi.3xx.com;        root /var/www/home/;                #代理连接超时时间        proxy_connect_timeout 5;                #代理传输超时时间        proxy_read_timeout 15;                #节点健康状态展示页面        location /sstatus {                check_status;                access_log off;                                #allow SOME.IP.ADD.RESS;                #deny all;        }    location / {        proxy_next_upstream http_502 http_504 error timeout invalid_header;        proxy_pass  ;        proxy_redirect     off;        proxy_set_header   Host             $host;        proxy_set_header   X-Real-IP        $remote_addr;        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;    }    access_log  /data/logs/$host.proxy.log  access; }

5.1.3 其他配置

C节点和D节点上,配置好域名ceshi.3xx.com的nginx+php服务即可。这里不细说。

Q机器上增加127.0.0.1 ceshi.3xx.com 到/etc/hosts。

完成上面配置后,本地pc再配置hosts: 10.*.*.101 ceshi.3xx.com,

就可以打开http://ceshi.3xx.com/sstatus,查看节点健康状态页面:

5.2 测试过程

通过在C节点上抓包,可以看到Q上nginx的健康检查是通过对配置中的80端口发起tcp 三次握手来实现检测的。从而我们设计后面的测试条件。

5.2.1 测试用例

C机上分别执行以下5种情况,同时Q机不断发送请求:

#nginx 退出:[root@10.*.*.32 ~]# seq 100|while read line ; do echo 1; killall nginx ; sleep 20; /root/nginx_start; sleep 20; done#php-fpm退出:[root@10.*.*.32 ~]# seq 100|while read line ; do echo 1; killall php-fpm ; sleep 20; /root/phpfpm_start; sleep 20; done#iptables禁止ip访问:[root@10.*.*.32 ~]# seq 100|while read line ; do echo 1; iptables -I INPUT -s 10.*.*.101 -j DROP; sleep 20; iptables -D INPUT -s 10.*.*.101 -j DROP; sleep 20; done#延迟5秒[root@10.*.*.32 ~]# tc qdisc add dev eth0 root netem delay 5000ms#丢包50%[root@10.*.*.32 ~]# tc qdisc add dev eth0 root netem loss 50%

5.2.2 测试结果

5.2.3 测试结论

1.在个别节点因为应用异常或网络异常导致完全不可用时,利用nginx反向代理和健康检查模块可以很好剔除故障节点,保证访问到可用节点。

2.在个别节点网络质量差时,可以提高请求到正常节点的命中率,在访问到异常节点失败后,反向代理继续请求正常节点,得到正常返回。

3.在全部节点都有间歇异常时,有概率判断全部节点不可用,返回502,这时跟不用反向代理差别不大。

这里我们实现的是优化服务器访问web接口,保证自动切换到正常节点。对于网页浏览器端访问web接口,我们可以做的不多,只能通过DNS控制玩家访问到的ip(源服务器或者bgp中转ip)。如果是手游客户端,还可以增加检测逻辑,在游戏客户端到游戏服务端有出现弱网的时候,把访问切到bgp中转IP。

6 总结

nginx除了提供日常的web服务,还能作为代理软件服务于各类场景。如本篇利用nginx的代理功能,加上自带或第三方模块,来实现全国业务访问的网络优化,以及自动选择可用网络节点来访问第三方业务。

END

全中国只有不到1% 的人关注了运维军团

你是个有眼光的人!

(由于交流群人数已超100人,需要进群的小伙伴可以添加运维小编的:Alxy0819)

如果你喜欢我们的文章,请转发到朋友圈

ywjtshare

运维军团

专注运维技术与传承,分享丰富原创干货