16

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

 5 years ago
source link: https://studygolang.com/articles/18761?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

背景

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

  • 他们客户端是很旧的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,看到这个信息:

bVbpwKN?w=1036&h=51

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

bVbpwLB?w=697&h=291

且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 = 8192
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 8192

这个值的含义见链接,简单说就是允许接收的最大并发数,我们压测工具跑的是100并发,实际只需要这个值是200就够了


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK