运维军团祝你元宵节快乐
小序:先感谢军粉们的支持,新的一年运维军团依然秉持给大家分享原创干货的宗旨。春节假期后的首篇文章,希望大家能够喜欢。
本期文章介绍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 install5.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
运维军团
专注运维技术与传承,分享丰富原创干货