精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
|
|||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||||||||||||||||||||
发表时间:2010-11-09
最后修改:2010-11-12
背景最近一直在做公司的应用软件服务架构的升级工作,里面涉及使用mod_proxy替换先前的mod_ajp,因为我们要用jetty7。
同时万恶的jetty 7对ajp协议支持不是很好, 具体可见我的另一篇博文: 纠结的mod_jk与jetty的组合。 在线下测试少量的请求没啥问题,一到线上跑个几分钟就开始抛异常了,查了jetty的mail list,也有人报类似的bug。
所以后续的工作重心还是回到mod_proxy_http上来,今天在调试mod_proxy配置时,出了一些小插曲,记录分享一下给大家,免得大家再走歧路。
配置需求大致url类型介绍: 目前公司的url基本是按模块进行划分,比如 http://域名/module/xxxx.html, 域名后多了一个module路径,用于区分不通的业务,比如home , admin , product等。
对mod_proxy的使用需求:
Apache mod_proxy模块介绍主要的资料还是来自于官方文档:http://httpd.apache.org/docs/2.2/mod/mod_proxy.html
涉及的主要配置原语:
其他具体配置含义不多做介绍,大家可以看官方文档。
实施过程1. 考虑mod_proxy需求1,保持长链接
这个mod_proxy本身就支持worker池的概念,不过需要配置一下几个参数:
最后的配置:
min=5 smax=16 ttl=600 timeout=20
说明:
2. 共享连接池配置思路一: 坏人匹配策略
mod_proxy进行proxy匹配时,是按照配置文件的顺序进行查找匹配,具体可见官方文档描述,直接贴英文。
The configured ProxyPass and ProxyPassMatch rules are checked in the order of configuration. The first rule that matches wins. So usually you should sort conflicting ProxyPass rules starting with the longest URLs first. Otherwise later rules for longer URLS will be hidden by any earlier rule which uses a leading substring of the URL. Note that there is some relation with worker sharing. For the same reasons exclusions must come before the general ProxyPass directives
说明:
思路二:好人匹配策略
华丽的分割线
小插曲:在实施ProxyPassMatch配置时,真正的被apache官方文档误导了一把,万恶的主啊。花费了我近一天的时间排查问题。希望大家可以引起重视
官方文档针对ProxyPassMatch有这么一个例子: 大体意思是也很好理解,说ProxyPassMatch可以通过$1,$2提取正则匹配的内容,并且添加在worker url之后,组成最终的目标url。
所以参照这官方的例子,我最初的配置就为:
ProxyPassMatch ^(home|admin|product|monitor)/(.*)$ http://localhost:7001/$1/$2 通过apache ab进行系统压力测试时,发现一个很严重的问题
./ab -k -c 15 -n 50000 http://10.20.156.49:2100/member/signin.htm -k 指定保持keepalive -c 并发数 -n 请求数 再通过netstat -nat命令看了下tcp状态,发现近2000左右的TIME_WAIT,在停止ab施压后,发现TIME_WAIT连接很快会得到释放 最后通过tcpdump在服务器上,发现了问题,每个请求都是走了新的socket链接,tcp链接快速打开,快速关闭,因此出现了大量了TIME_WAIT状态。针对tcpdump的使用介绍,可以查看我的另一篇博文:tcp链接的几种状态&tcpdump抓包
tcpdump -s 0 -i lo port 2200 -nn 说明:port 2200为后端应用服务端口,-i 必须指定为loopback网络接口,因为apache和后端应用之间走的是loopback网络接口 网上google了一把无果,也在stackoverflow论坛上逛了一圈,没发现有类似的question提问。最终很无奈,在查看apache maillist的时候,发现了这么一个bug。
Bug 43513 - Persistent backend connections for ProxyPassMatch
ProxyPassMatch creates a worker like ProxyPass does,but it uses regex URI for a worker name. For example, your httpd.conf: ProxyPassMatch ^/test/(\d+)/foo.jpg http://backend.example.com/$1/foo.jpg then worker name is "http://backend.example.com/$1/foo.jpg", so URL never matches and the worker is no longer used.打开了apache的LogLevel为debug,看到了的确建立了以$1/$2为url的worker池 的确,我在测试时
[Tue Nov 09 22:12:06 2010] [debug] proxy_util.c(1818): proxy: grabbed scoreboard slot 0 in child 7897 for worker http://localhost:2200/$1/$2 [Tue Nov 09 22:12:06 2010] [debug] proxy_util.c(1837): proxy: worker http://localhost:2200/$1/$2 already initialized
按照bug的描述,因为通过最终http://localhost:7001/$1/$2,经过$1,$2渲染后最终的url是一个真实的目标url,它与对应的worker url不匹配,所以无法使用该worker的pool池配置。
最后调整配置为:
ProxyPassMatch ^/(home|admin|product|monitor)/(.*)$ http://localhost:7001 分析:
注意最后的worker url没有加$1/$2,而是直接使用了/目录,mod_proxy在匹配到ProxyPassMatch后,会将整个URI和worker url进行拼接,最终的url为: http://localhost:7001/admin/xxx.html,再根据mod_proxy针对worker sharing,子目录url可以重用父目录url的worker连接池。所以这里/admin/xxx.html可以重用/的连接池,这样就实现了公用。
在最后的测试中,抓了下包,基本没有出现TIME_WAIT的异常情况,问题得到圆满解决,希望本文对mod_proxy的使用对你能有所帮助。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||
发表时间:2010-11-11
不错。 很完整。
|
|||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||
发表时间:2010-11-12
好文章,写的很深入而且易懂。 “tcp链接的几种状态&tcpdump抓包”是个死链接,望楼主修正下。
几个问题: 1 mod_proxy本身就支持worker池:这个连接池是存储“apache服务器”到“目标服务器”(localhost:7001)的连接吗?如果用了正着表达试,就要重复建立多个worker池用于连接目标服务器吗? 引用 ProxyPassMatch ^(home|admin|product|monitor)/(.*)$ http://localhost:7001/$1/$2
2 代理的使用经常存在安全的问题,除了通过设置合理的url来保护代理能访问的服务外,还有其他常用机制吗?比如在代理模块之前增加认证模块。 |
|||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||
发表时间:2010-11-12
最后修改:2010-11-12
tonynju 写道 好文章,写的很深入而且易懂。 “tcp链接的几种状态&tcpdump抓包”是个死链接,望楼主修正下。
几个问题: 1 mod_proxy本身就支持worker池:这个连接池是存储“apache服务器”到“目标服务器”(localhost:7001)的连接吗?如果用了正着表达试,就要重复建立多个worker池用于连接目标服务器吗? 引用 ProxyPassMatch ^(home|admin|product|monitor)/(.*)$ http://localhost:7001/$1/$2
2 代理的使用经常存在安全的问题,除了通过设置合理的url来保护代理能访问的服务外,还有其他常用机制吗?比如在代理模块之前增加认证模块。 多谢,死链接问题已经修改,可以查看:http://agapple.iteye.com/blog/806518 问题: 1. 连接池是指apache进行proxy的代理时,与后端的应用建立的tcp连接。从提交的bug描述来看(也可能不算bug),如果使用了http://localhost:7001/$1/$2,apache建立的worker名字即为http://localhost:7001/$1/$2(你可以看下apache debug日志),而每次渲染$1,$2后拿到的url是一个完成的url,去找匹配的worker池就找不到了,名字不同了,无法使用原先的worker池,因此每次都是新建tcp socket链接,从我抓包看到的现象就是这样。 2. 至于安全管理,我个人认为mod_proxy只是做为一个代理服务管理,不应该关注太多,管理后资源分发即可。至于这个资源是否允许被用户访问,应该是后端应用自己去保证,比如应用的权限控制体系。这样以后应用重构,拆分才能更加easy。 apache mod_proxy倒是有些安全管理的功能,比如端口限制,访问次数控制,这个也是更多在系统层面做的控制 |
|||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||
发表时间:2010-11-12
最后分析的问题很隐蔽啊。
|
|||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||
浏览 7615 次