在windows下做7層軟負載做了一些分析,對負載這塊有興趣的你,可以來看看哦。其實所謂四層就是基於IP+端口的負載均衡;七層就是基於URL等應用層信息的負載均衡;你對7層,有了淺顯的印象吧,那大家有啥做7層軟負載的經驗可以討論分享一下呢,當然最好是windows平臺下的。
可靠性分析
為了容災,提高可靠性,考慮如下方案
1. 7層軟負載的前面要有4層負載設備,7層軟負載多臺,且共享哈希策略,4層設備按Session做隨機負載,這樣所有的7層軟負載機器均可正確處理任何一個請求,且某臺7層軟負載宕機後,剩下的7層軟負載可繼續工作,由於4層負載有keepalive功能,可以檢測出哪臺7層軟負載宕機了,並且不給其轉發請求。
2. 7層軟負載做雙擊熱備,7層軟負載直接接入外網,正常情況下由主服務器處理請求,如果主服務器宕機,備份服務器發現後,通過ARP欺騙獲取主服務器原有 IP,以把請求吸引到備份服務器上處理(硬件如果支持可能可以考慮主備機共享一個MAC地址),主備切換時可能會造成短時請求失敗的現象。
綜合考慮,第二個方案有些山寨和不保險,優先考慮第一個方案。
性能分析
1、
對外網的連接管理和協議解析使用http.sys(HttpApi.dll,HttpListener)內置機制,http.sys在內核級別進行HTTP的連接管理和協議解析,性能應該可以保證。
2、 對內網RealServer的連接管理和拼包使用HttpWebRequest的內置機制,但有如下問題
a)
連接管理:默認Proxy向RealServer發送請求會新建立一個連接,收到應答後會拆除連接,也就是說Proxy和RealServer之間會建立大量連接,但是由於受端口(65535)限制,出站連接不可能太多。這個問題要想辦法解決,可以嘗試把RealServer啟用KeepAlive解決。
b) 拼包:HttpListener收到包後,雖然自動已經解析成對象,但是還要把這些包重新拼成HttpWebRequest的格式發給
RealServer,這裡麵包括拷貝Uri,HttpHeader,Cookies,Body等,這些數據量挺大的,在內存中拷貝一遍肯定損耗性能。該問題應該無法規避。
3、如果是常規的web應用(資源訪問類),Request小,Response很大,RealServer返回Response時還要經過Proxy,還要進行內存拷貝,這個也非常影響性能。然後7層又做不到LVS的那種DirectRoute機制(需要修改網絡包的mac地址),實現IP隧道和TCP的狀態遷移需要修改操作系統的TCP/IP協議棧。鑑於代價太大,該問題也無法規避。
4、 Http協議規定請求和應答必須成對出現,默認情況下一條連接上發送出去請求後要等到收到該請求對應的應答後才能發送下一個請求,雖然Http1.1有
pipeline功能,可以成批發送請求,不必先等待應答,但是也有諸多限制,比如規定了POST不應該使用pipeline,一條連接上第一次發送請求也不可以使用pipeline機制,還有每批請求的請求數也不好定奪,批量發送請求後,如果連接斷開,會有多個請求失敗,等等。HTTP協議不像SIP協議那樣靠CallID和Cseq來匹配請求和應答,那樣可以純異步的收發請求和應答,所以在實現Http協議棧時要同步等待應答,然後該連接上才能發送下一批請求,這必然會影響性能。
5、
HttpListener的異步接收請求和發送應答是普通的APM模式(BeginXXX,EndXXX格式),這種異步模式在頻繁調用時會大量產生和銷燬IAsyncRequest對象,從而增加了GC的壓力,而且IAsyncRequest對象還沒有提供自定義池化的接口。如果
HttpListener提供了新的基於事件的異步模式(XXXAsync(eventargs)模式,參考Socket.ReceiveAsync方法)會解決這個問題。
6、另外由於HttpLisenter是.net的包裝類,在用戶態執行,而HTTP.SYS是內核態運行,在接受請求,返回應答會進行兩次用戶態和內核態之間的切換,從而降低性能,如果能在內核態直接進行7層轉發就好了,在linux下LVS(KTCPVS)可以做到內核態的基於內容的7層轉發,在
windows下可能需要做TDI或者NDIS開發,查了些資料,太複雜了,所以也不考慮了先。
單元測試
場景設計:
比如一個獲取用戶頭像的請求,用戶的頭像存放在多臺DB裡,並由多個web服務器(webserver1,webserver2)緩存頭像並根據用戶的HTTP請求返回給客戶端用戶頭像,由於web服務器緩存了用戶頭像,是有狀態服務,所以HTTP請求裡要帶userid參數,7層負載根據
userid做哈希後把請求路由給緩存該userid對應用戶頭像的web服務器。
請求格式:
GET /getportrait.aspx?userid={userid}
其中{userid}是Int32類型,路由算法是{userid} mod 2 = 0的話路由給webserver1 ,{userid} mod 2 =
1的話路由給webserver2
應答格式:
200 OK HTTP1.0
Content-Length:5
Content-Type:text/txt
{userportrait}
其中為了測試方便{userportrait}為文本格式,就是webserver本身的機器名字
測試用例:
請求GET /getportrait.aspx?userid=1111,預期返回應答webserver2
請求GET /getportrait.aspx?userid=2222,預期返回應答webserver1
具體測試userid可隨機生成整數,並根據是否可被2整除對應答進行預期。
性能測試
測試準備:
兩臺物理機RealServer1和RealServer2,一臺軟負載機器SoftProxy,兩臺測試機TestClient1,TestClient2。
其中SoftProxy的配置:Xeno 3.0G(16核),16G內存,windows2003 x64, 千M網卡(先不考慮雙網卡均衡)。
RealServer配置:Xeno 1.86G(4核),8G內存,windows 2003 x86
部署:
RealServer1和RealServer2部署具有返回用戶頭像的服務,SoftProxy部署7層軟負載,TestClient1和TestClient2部署LoadRunner及測試腳本進行測試。
測試模型:
在線用戶:300個虛擬用戶,每個虛擬用戶模擬1000客戶端,共模擬300000在線用戶,每個用戶每5秒獲取一次頭像。
測試預期:
預期SoftProxy每秒處理6w的獲取頭像請求,並且CPU利用率在80%以下,內存利用率在5G以下。
其它問題
1、 客戶端IP
a) 因為RealServer接收的是SoftProxy的請求,不能直接知道客戶端IP,所以SoftProxy需要在轉發包的時候加上一個http
header以告訴客戶端IP
2、 重定向,身份驗證,臨時應答,緩存等問題
a) httpRequest.ServicePoint.Expect100Continue = false;
b) httpRequest.ServicePoint.UseNagleAlgorithm = false;
c) httpRequest.AllowWriteStreamBuffering = false;
d) httpRequest.AllowAutoRedirect = false;
e) httpRequest.AuthenticationLevel = AuthenticationLevel.None;
f) httpRequest.AutomaticDecompression = DecompressionMethods.None;
g) HttpRequestCachePolicy noCachePolicy =
new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
httpRequest.CachePolicy = noCachePolicy;
3、 Cookies咋辦?
a)
HttpWebRequest並不支持直接寫cookie,只能創建cookie容器,等應答回來後才會有cookies,這個比較鬱悶,暫時如下這樣寫,收到RealServer的應答後把應答裡的Cookies複製給Listenresponse並返回給客戶端
httpRequest.CookieContainer = new CookieContainer();
HttpWebResponse httpResponse =
(HttpWebResponse)httpRequest.GetResponse();
listenresponse.Cookies = httpResponse.Cookies;
4、 超時值,不好定奪
a) httpRequest.Timeout = 20;
b) httpRequest.ReadWriteTimeout = 10;
對windows下做7層軟負載做了分析,來源筆記本w7系統下載 2013最新版kwlogistics.cn,感覺最不靠譜的就是HttpWebRequest,這玩意實現太複雜,包裝太深,而且也不是設計為發送大量出站HTTP連接用的,HttpListener應該還行,就是設計為做HTTP服務器用的,實在不行Proxy和RealServer之間用
Remoting傳遞HTTP信息,然後兩邊把Remoting再轉換成HTTP信息。