我司的軟件在一個客戶處測試功能和性能,這個客戶比較特殊:java
http1.1
,但又不帶host
這個http頭最開始是請求直接返400,nginx access log能夠看到400可是沒有更多信息,error log則沒有任何信息打印,一開始另外一位同事負責定位,我跟着一塊兒用wireshark抓包看了好久,沒得出結論。後來我又看了一下,nginx error log默認的日誌級別是crit,那麼直接改到debug,看到這個信息:node
那麼問題就一目瞭然了,查了一下,這個header是http1.1要求必須帶的python
且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
可是到這還沒結束,壓測跑了一下子發現請求所有失敗,看了一下報錯,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應該也能作到無損耗的,暫時沒有再去研究,但從簡單使用來看,腳本語言畢竟是腳本語言,你大爺仍是你大爺。