WEB应用

分享一个Nginx反向代理的另类应用案例

博客前面分享了一篇《分享一个Nginx正向代理的另类应用案例》,时隔不久,身为救火队员、万金油的博主又再一次接到了一个另「W」类「T」需「F」求: 场景和上次有些类似,也是部门引进的第三方应用,部署在各个网络区域,从OA办公区域无法直接访问。目前,运营人员都需要登陆Windows跳板机,才能打开这些应用的WEB控制台。既不方便,而且还有一定Windows服务器的维护工作量,于是找到我们团队,希望通过运维手段来解决。 拿到这个需求后,我先问了下各个应用的基本情况,得知每个应用的框架基本是一样的,都是通过IP+端口直接访问,页面path也基本一样,没有唯一性。然后拿到了一个应用WEB控制台地址看了下,发现html引用的地址都是相对路径。 乍一想,这用Nginx代理不好弄吧?页面path一样,没法根据 location 来反代到不同的后端,只能通过不同Nginx端口来区分,那就太麻烦了!每次他们新上一个应用,我们就得多加一个新端口来映射,这种的尾大不掉、绵绵不绝事情坚决不干,Say pass。 再一想,我就想到了上次那个正向代理另类应用方案,感觉可以拿过来改改做动态代理。原理也简单:先和用户约定一个访问形式,比如: Nginx代理地址为myproxy.oa.com,需要代理到IP为 192.168.2.100:8080 的控制器,用户需要访问http://myproxy.oa.com/192.168.2.100:8080/path。 动态代理的原理及实现: 1、Nginx从$request_uri变量中,通过斜杠提取第一段作为要反向代理的对象,即proxy_pass,提取后面的作为需要反代的路径; 2、对于Html、JS、CSS等资源引用则需要通过Nginx的替换模块,将路径替换为上述约定形式,比如:Html里面的href="/js/jquery.min.js",需要替换为href="http://myproxy.oa.com/192.168.2.100:8080/js/juqery.min.js",即所有资源地址都保证符合代理约定的形式,才能够正确走代理获取。 3、通过代理去访问,查看浏览器开发者工具中的Network和console,找到无法访问的地址,并分析引用的位置,写规则替换掉即可。 4、实际测试发现,他们的应用可能还会有https协议(...),而且是伪证书模式,只是开了https协议访问。上述设计模式下,https页面是无法打开的,这里需要兼容https后端才行,因此最后的约定形式简单修改为:如果是 http://myproxy.oa.com/https-192.168.2.101:8080/path,即:如果是https协议,需要在第一段path的IP前面加上https-来区分,而http协议则可加可不加。 基本通过上述几步,就完全搞定了,最终Nginx规则如下: Tips:实际调试过程中,可以给Nginx集成一个echo模块,可以将变量打印出来,方便调试。 最后,在Nginx服务器的/html目录放一个index.html导航页面,用户只需要访问代理地址http://myproxy.oa.com/,就能看到全部的后端节点,点击访问即可,真的不要太爽哦! 不得不再一次感慨,Nginx真是一个好东西,完美~
阅读全文
WEB应用

惊现Haproxy重复添加X-Forwarded-For问题(附官方解决办法)

最近在配置Haproxy代理的时候发现一个很有意思的事情:Haproxy在代理http请求会无脑加一个X-Forwarded-For(后文简称XFF),而不是将自身的IP地址加到已存在的XFF列表之后,WTF!还有这种神操作? 确认无误之后,我到Haproxy的github开了一个issue反馈了这个BUG(issue地址),最终了解到了Haproxy就是这样设计的,并得到了解决方案,而且这个issue的回复很有意思,特来博客分享下。 刚开始,我的issue提到Haproxy没有将自身IP地址append到已有的XFF列表之后,而是无脑又加了一个,这应该是个BUG: 官方开发GG回复让我升级到最新稳定版,我说升级了也是一样的,结果人家又回复我说Haproxy本来就是这样设计的: 我接着回复说Haproxy这样设计会导致很多开源程序获取真实IP异常,比如Twisted和packetbeat,但是官方说Haproxy 的设计100%符合HTTP协议标准balabala....既然都这样说了,我能说啥呢?只好用官方给的建议选项if none来拒绝Haproxy添加XFF,先解决我程序获取源IP错误的问题。 本以为这样就结束了,结果高潮来了! 一位很酷的法国大胡子发起了热心支援: 他的大概意思是说,既然Haproxy 100% 符合HTTP标准,那为啥没有遵循 XFF 的标准约定,将自身的IP地址添加到已存在的XFF列表末尾??也提到了多个XFF会导致很多程序无法读取,比如tomcat-8.5。为啥不加一个选项来选择使用多个XFF还是使用一个XFF等等balabala一顿说... 接着官方在HTTP标准上发起反驳解释(一大堆内容,此处不表),并在最后说明这样做是为了提高Haproxy性能,如果先判断是否存在XFF在高并发情况下性能大概下降2-3倍(非特指Haproxy)。 当然,官方最终还是给了一个解决办法,能够让Haproxy也像Nginx那样将自己的IP地址加到已有XFF之后,只需在Haproxy新增如下配置即可: 虽然官方给的答复可以解决问题,不过法国大胡子最后回复的一段话我觉得说得非常好: 大致意思是,我已经知道如何通过配置来解决,但是为啥 option forwardfor 这个选项没有和大部分人预期那样来设计与开发,而且搞得巨复杂? 然后直接给出他认为更好的开发设计,比如用 option forwardfor force 替代: 实现强制覆盖XFF,又比如用 option forwardfor append 来替代: 实现将自身IP地址加到已有的XFF之后。很明显,这样的设计才更有可读性,更好理解!他在最后还提到了,Apache/Nginx/Tomcat/Jetty/F5等等都是将自身IP地址添加到XFF之后,难道你Haproxy认为这些软件的使用率还不够高??喷得大快人心,再次赞一下法国大胡子! 总之,真的是很有意思的一个issue,同时也解决了问题,发现同样问题的朋友可以参考解决!
阅读全文
WEB应用

Haproxy进阶管理:命令行控制后端节点上下线

很多业务系统都用到了Haproxy这个高性能反向代理负载均衡器。在日常运维当中,Haproxy后端节点的上(接入)、下(剔除)线操作绝对是家常便饭,而且人工重启的时候经常有胆颤心惊的感觉。 下面分享一种命令行操作Haproxy后端节点平滑上下线的技巧。 一、新增配置 Haproxy自带了一个非常实用的管理页面,我们可以在harpxoy.cfg新增如下配置,开启Haproxy监控管理页面功能: 配置后,重启Haproxy,访问 http://ipaddress:8080/admin,使用admin/admin登陆之后就能看到管理页面了: 二、管理功能 因为我们还配置了管理功能,所以在各个backend都能看到如下管理功能: 我们在左侧勾选好对应的后端节点,选择需要转换的状态点击Apply就能完成后端节点的状态切换。 三、平滑发布 对于平滑发布来说,这里用得比较多的2个选项是READY(就绪状态)和MAINT(维护状态)。 READY 表示被勾选的节点已经完成维护,Apply进入就绪状态后,Haproxy会自动发起健康检查,如果检查通过,这些节点将进入映射状态,接受映射请求了。 MAINT 表示被勾选的节点需要进行维护,Apply进入维护状态后,Haproxy将会停止往这些节点转发请求,并等待已有的请求结束连接。 通过这个功能,我们就能对业务进行从容发布了,比如我们有一个业务有2个节点,我们可以先将其中一个节点改为MAINT状态,刷新Haproxy管理页面,当看到Session里面的Cur(当前连接)为0个时,我们就可以从容的对这个节点进行发布、重启等维护操作,完成维护后我们在将这个节点改为READY状态即可。接着,我们同样操作剩下节点即可(节点剔除后带来的性能下降问题,这里就不展开了讨论了)。 四、命令行操作 很明显,这个功能非常实用,但是并不方便,因为需要手工操作,没法嵌入到自动化发布流程当中。不过通过分析POST请求,可以得出curl命令行操作方法: s 表示后端标签名 action 表示状态 b 表示backend标签名 通过测试,得出curl发起请求格式如下: 比如,如果Haproxy有一个后端如下配置: 那么,业务系统发布之前,我们将192.168.1.1这个节点改为维护状态,则如下发起请求即可: Ps:要注意的是,这个POST参数必须URL转码,比如存在冒号【:】,需要转换为 %3A才行。 业务系统发布之后,我们再发起node1上线请求: 后面我们只需要重复操作node2节点的上下线即可完成无损发布了。这一整套动作就可以整合到自动化发布流程当中,不再需要人工介入。 五、小结 本文介绍了Haproxy开启管理功能的配置方法以及命令行操作后端上下线的技巧,为程序平滑部署、系统自动化运维提供了一种更加简单的解决方案。 拓展:在复杂的业务场景中,可能用到了etcd+confd + haproxy的统一配置管理方案,原理是通过更改Haproxy配置,然后热重启Haproxy(-st 指令)来上下线节点,是非常不错的方案!不过,根据我个人经验,在高频业务场景中,剔除后端节点再热重启Haproxy,可能出现业务请求异常问题。
阅读全文
WEB应用

Haproxy安装部署文档及多配置文件管理方案

最近我在负责一个统一接入层的建设项目,涉及到Haproxy和ospf的运维部署,本文分享一下我在部署Haproxy之后整理的运维部署规范,并实现了Haproxy的多配置文件管理方案。 一、部署安装 1、下载源码包 最新stable版本下载地址:http://www.haproxy.org/download/1.7/src/haproxy-1.7.9.tar.gz 2、编译安装 3、创建目录 二、软件配置 熟悉Nginx和Apache的朋友都知道,这两个Webservice都支持include加载多个配置文件的语法,但是Haproxy并不支持!如果现网映射规则非常多,那么haproxy.cfg这个配置文件就跟臭袜子一样,又臭又长! 因此,我也是翻遍了国外的各种论坛帖子,终于发现一种变相实现Haproxy多配置文件的方案。其实,Hparoxy是支持多配置文件的,但是不是include语法,而是在启动的时候多次使用-f 拼接配置文件,比如: 因此,我们可以在配置文件目录以及启动脚本上做点改变,让Haproxy支持多配置文件。 1、路径约定: 待上线的 tcp 映射规则存放目录:/usr/local/haproxy/conf/ready/tcp 待上线的 http 映射规则存放目录:/usr/local/haproxy/conf/ready/http 已上线的 tcp 映射规则存放目录:/usr/local/haproxy/conf/enabled/tcp 已上线的 http 映射规则存放目录:/usr/local/haproxy/conf/enabled/http Ps:本文为多配置模式,enabled 里面的配置为软链接形式,软链接至ready对应配置文件,方便管理。 2、配置模板 ①、主配置:haproxy.cfg ②、http 扩展配置文件模板 ③、tcp 扩展配置文件模板 Ps:多配置模式中,多个frontend必须绑定不同的IP或者端口,否则数据会串,导致映射到不同的后端而报错。因此,同一个IP+端口下的映射务必配置到同一个frontend模块内。 三、系统服务 1、服务脚本 对比已有的Haproxy脚本,我编写的时候新增了如下实用功能: 支持配置文件语法测试 支持进程的监控(自拉起)功能 重启之前会先检测配置语法,规避因配置错误导致重启后进程挂掉 支持多配置文件模式(按照前文约定目录存放拓展配置,脚本将自动识别) 下面是服务脚本代码: 保存为 /usr/local/haproxy/sbin/ctrl.sh,赋可执行权限,如下注册系统服务: 服务控制: 2、配置自拉起 全部完成后,最终目录结构如下: 四、日志配置 配置rsyslog 五、小结 以上内容就是我对Haproxy部署规范的整理,并通过拼接方式变相实现了Haproxy的多配置文件管理。当然,略遗憾的是未能实现Haproxy的WEB管理方案,这个有待继续研究实现,敬请期待!
阅读全文
WEB应用

libmemcached编译安装报错解决记录

我负责的几个公司内部网站,仅集成了php原生memcache组件,不支持memcached分片存储的自动容灾方案,近期出现过几例因memcache服务器故障引起WEB爆卡的尴尬事,所以接到了一个给现网php集成memcached模块的需求。 内部的个别系统有多老、多难用我就不吐槽了,slackware、suse用过的人都知道。。。不说了,总之老老实实的编译安装吧。 memcached这个php模块依赖于libmemcached,所以集成前先要编译安装libmemcached。 按照常规编译方法,对libmemcached进行编译安装,结果如下报错: error: cinttypes: No such file or directory 查了下资料,发现是因为gcc版本过低,看了下系统当前的gcc版本,是4.1.2,决定升级之。 简单记录下gcc编译过程: 1、安装gmp 2、安装mpfr 4、安装mpc 5、安装gcc 对于这种老掉牙的服务器、程序,编译安装gcc的时候也不敢直接全局覆盖安装(编译不指定路径),于是将gcc-4.5.1安装到/usr/local/gcc-4.5.1 Ps:更多可选参数请参考官方文档。gcc编译安装必须注意依赖包的顺序,可谓环环相扣。 编译安装后,由于是指定的安装路径,所以系统用的依然是原来的gcc,所以为了本次编译libmemcached,需要将新版本软链过去,暂时使用(简单方案) 进入libmemcached源码目录继续编译,结果如下报错: error: bits/c++0x_warning.h: No such file or directory error: cstdint: No such file or directory error: tr1_impl/cinttypes: No such file or directory 真是醉人,明明都升级了还报错!没办法,继续耐着性子看信息,发现libmemcached在configure之后有如下统计信息: 赫然发现了图中还有个c++显示是4.1.2的老版本!!!于是,原来把c++给漏了,顺手补之: 再去编译安装,就行云流水,再无报错!后面编译memcached就不多说了,不会的可以参考前文教程。最后,记得取消gcc和c++的软链接,还原到4.1.2版本即可(当然,若无异常也可以继续保留)。
阅读全文
WEB应用

修改Apache的超时设置,解决长连接请求超时问题

某日,组内后台开发找到我,问我们的WEB服务器超时设置是多少。他反馈的问题是,有一个VLAN切换任务cgi接口经常返回504网关超时错误,要我分析解决下。 我问了一下,得知这个请求遇到网络设备对象较多的时候,需要小半个小时才能完成,也就是要用到长连接才行。 老规矩,从开发那拿到接口地址,得到接入层服务器IP,是一台Haproxy代理,看了一下Haproxy的超时设置: 各种1小时超时,所以排除Haproxy的影响,继续往下看。 Haproxy 代理的是2台Apache,也就是部署了cgi接口的服务器。第一时间查看了 httpd.conf 和 httpd-vhost.conf 中的配置,居然没找到超时设置。 于是,搜索了下相关教程,发现原来藏在了 httpd-default.conf 当中: 看了下,这些是Apache的默认配置,Apache也没有include到httpd.conf当中。因此,编辑 httpd.conf,找到如下参数: 去掉注释,保存文件。然后再编辑 /usr/local/apache2/conf/extra/httpd-default.conf 文件,将Timeout的值修改为符合生产环境要求的1800秒,最后执行Apache平滑重启命令即可: Ps:我之前一直以为只有Nginx有一个平滑reload命令,后面才知道Apache、Haproxy都支持平滑重启名称,这个非常棒! 重载之后,就不会出现504网关超时设置了。
阅读全文