乐趣区

记录一次windows server上,反向代理服务器的配置和使用

背景
我司的软件在一个客户处测试功能和性能,这个客户比较特殊:

他们客户端是很旧的 java 代码,且要求不能改动,客户端的主要业务简单说就是上传下载文件
他们提供了客户端 demo,http 请求是用裸 socket 手动加 http 头,写死了 http1.1,但又不带 ’host’ 这个 http header
客户要求中间必须经过一台 windows server 服务器代理
后端的实际服务器是 linux 系统,用的是 nginx

host header 问题(此时先直连后端服务,不考虑代理)
最开始是请求直接返 400,nginx access log 可以看到 400 但是没有更多信息,error log 则没有任何信息打印,一开始另一位同事负责定位,我跟着一起用 wireshark 抓包看了很久,没得出结论。后来我又看了一下,nginx error log 默认的日志级别是 crit,那么直接改到 debug,看到这个信息:

那么问题就一目了然了,查了一下,这个 header 是 http1.1 要求必须带的

且 nginx 严格遵守该协议,没有提供可配置的方式忽略这个头,按理说其实服务端不应该强行处理这种问题,但客户要求最高,没办法
这时候好在,正好我们需要一层反向代理,那么,看看能不能找一个允许不带该 header 的反向代理服务器实现,接下来可以暂时忽略这个问题,我们使用压测工具测性能,压测工具在这个 header 上是没有问题的
代理布署及性能问题
windows server 系统的服务器,一开始我们直接用 Nginx,但简单测后就知道性能很差,搜了一下基本是说 nginx 和 apache 在 windows 上性能都没啥希望,首推的基本还是微软自家的 IIS,于是我们配起了 IIS,果然性能与直连后端相比基本没有损耗,但是经过很长时间查资料,找不到配置忽略 host header 的方法,而且 IIS 的确不好用,配置比较难看懂,大家都不熟悉 windows 平台,接下来只能另辟蹊径
python:老本行,用 twisted 写了个 4 行的反向代理,性能比 nginx 倒是好一点,但大概也只有直连的 1 /6,时间紧迫,没来得及分析,继续尝试其他语言 nodejs:在 github 找到个 redbird 库,代码也是只需要两行,但性能跟 python 半斤八两 java:捡了个 undertow 的框架,折腾挺久终于搞起来,倒是基本没有性能损耗,于是就要解决 header 问题,但是这个版本的 400 返回没带提示信息,java 框架源码要反编译看,这个倒还好,但是没有错误信息,不好直接搜代码,只能看流程,比较难看 go:代码倒是长一些,要二三十行,性能不出意外也是等于直连,惊喜的来了,它的 400 带了个错误信息提示:missing required Host header,当时那个幸福感。。。无法形容,直接对 go 产生了满分好感于是直接打开源码目录全局搜,找到 src/net/http/server.go,如下一段 `
// hosts, haveHost := req.Header[“Host”]
isH2Upgrade := req.isH2Upgrade()
// if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != “CONNECT” {
// return nil, badRequestError(“missing required Host header”)
// }
// if len(hosts) > 1 {
// return nil, badRequestError(“too many Host headers”)
// }
// if len(hosts) == 1 && !httpguts.ValidHostHeader(hosts[0]) {
// return nil, badRequestError(“malformed Host header”)
// }
` 果断注释掉了上面这些,跑起来没有问题。但是到这还没结束,压测跑了一会儿发现请求全部失败,看了一下报错,socket 爆了,在 cmd 里 netstat 查了一下,果然 go 进程接近 2w 的 socket 消耗,全部是 TIME_WAIT 状态
查一下就知道,本端主动关闭的 socket,就会进入该状态,被对方关闭是 CLOSE_WAIT。那么查一下,有说设置注册表的 [HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesTcpipParameters]”TcpTimedWaitDelay”=dword:0000001e
感觉并不是解决办法?实测也不能解决问题。想想就知道,关键应该是找到为什么 go 会频繁关闭 socket,那么 google 的关键字就应该是这样了:go socket time_wait(而不是 windows socket time_wait)
搜索结果第一条 stackoverflow 的就是答案:https://stackoverflow.com/que… 在 main 函数里加上配置:http.DefaultTransport.(*http.Transport).MaxIdleConns = 8192http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 8192 这个值的含义见链接,简单说就是允许接收的最大并发数,我们压测工具跑的是 100 并发,实际只需要这个值是 200 就够了

退出移动版