記錄一次windows server上,反向代理服務器的配置和使用

背景

我司的軟件在一個客戶處測試功能和性能,這個客戶比較特殊:java

  • 他們客戶端是很舊的java代碼,且要求不能改動,客戶端的主要業務簡單說就是上傳下載文件
  • 他們提供了客戶端demo,http請求是用裸socket手動加http頭,寫死了http1.1,但又不帶host這個http頭
  • 客戶要求中間必須通過一臺windows server服務器代理
  • 後端的實際服務器是linux系統,用的是nginx

host header問題(此時先直連後端服務,不考慮代理)

最開始是請求直接返400,nginx access log能夠看到400可是沒有更多信息,error log則沒有任何信息打印,一開始另外一位同事負責定位,我跟着一塊兒用wireshark抓包看了好久,沒得出結論。後來我又看了一下,nginx error log默認的日誌級別是crit,那麼直接改到debug,看到這個信息:node

clipboard.png

那麼問題就一目瞭然了,查了一下,這個header是http1.1要求必須帶的python

clipboard.png

且nginx嚴格遵照該協議,沒有提供可配置的方式忽略這個頭,如上圖按理說服務端不該該強行處理這種問題,但客戶要求最高,沒辦法linux

這時候好在,正好咱們須要一層反向代理,那麼,看看能不能找一個容許不帶該header的反向代理服務器實現,接下來能夠暫時忽略這個問題,咱們使用壓測工具測性能,壓測工具在這個header上是沒有問題的nginx

代理佈署及性能問題

windows server系統的服務器,一開始咱們直接用Nginx,但簡單測後就知道性能不好,搜了一下基本是說nginx和apache在windows上性能都沒啥但願,首推的基本仍是微軟自家的IIS,因而咱們配起了IIS,果真性能與直連後端相比基本沒有損耗,可是通過很長時間查資料,找不到配置忽略host header的方法,並且IIS的確很差用,配置比較難看懂,你們都不熟悉windows平臺,接下來只能另闢蹊徑git

python:老本行,用twisted寫了個4行的反向代理,性能不如nginx,大概只有直連的1/6,時間緊迫,沒來得及分析,繼續嘗試其餘語言
nodejs:在github找到個redbird庫,代碼也是隻須要兩行,但性能跟python半斤八兩
java:撿了個undertow的框架,折騰挺久終於搞起來,卻是基本沒有性能損耗,因而就要解決header問題,可是這個版本的400返回沒帶提示信息,java框架源碼要反編譯看,倒也還好,可是沒有錯誤信息,很差直接搜代碼,只能看流程,比較難看,java接觸的也少
go:代碼卻是長一些,有三十來行,可是隻用到了go的標準庫,性能不出意外也是等於直連,驚喜的來了,它的400帶了個錯誤信息提示:missing required Host header,當時那個幸福感。。。沒法形容,直接對go產生了滿分好感
因而直接打開源碼目錄全局搜,找到src/net/http/server.go,以下一段
`github

// 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")
// }

`
註釋掉了上面這些,跑起來沒有問題,這樣host header的問題就解決了。golang

golang socket使用問題

可是到這還沒結束,壓測跑了一下子發現請求所有失敗,看了一下報錯,socket爆了,在cmd裏netstat查了一下,果真go進程接近2w的socket消耗,所有是TIME_WAIT狀態apache

本端主動關閉的socket,就會進入TIME_WAIT狀態,被對方關閉是CLOSE_WAIT。那麼查一下windows socket time_wait,有說設置註冊表的
[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetservicesTcpipParameters]
"TcpTimedWaitDelay"=dword:0000001ewindows

感受並非解決辦法?實測也不能解決問題。想一想也知道關鍵應該是找到爲何go會頻繁關閉socket,那麼google的關鍵字就應該是這樣了:go socket time_wait

搜索結果第一條stackoverflow的就是答案:https://stackoverflow.com/que...
在main函數里加上配置:
http.DefaultTransport.(*http.Transport).MaxIdleConns = 8192
http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 8192
這個值的含義見連接,簡單說就是容許保持的最大tcp鏈接數,默認值是2(待研究爲何要這樣默認),超事後會一直關socket再重開,咱們壓測工具跑的是100併發,實際只須要這個值是200就夠了(由於往real server的那個方向還須要一樣的鏈接數 因此*2)

想一想python應該也能作到無損耗的,暫時沒有再去研究,但從簡單使用來看,腳本語言畢竟是腳本語言,你大爺仍是你大爺。