異步機制(Asynchronous) -- (四)缺點兼談系統測試

上篇

這是這個系列的最後一篇了,是我在春節期間陸陸續續寫的,所以可能不是很順暢....

之前列了很多異步機制的用法和好處,這裏寫寫它的缺點。毫無疑問,異步機制很難用是衆所周知的一個問題,原因在前面的幾篇中也解釋過了,因爲你需要將同步機制中邏輯上順序出現的代碼切割成獨立的幾個小塊,然後要非常小心的處理各個代碼塊之間的關係。
不過這裏想解釋的是另外一個問題,就是異步機制的系統很容易陷入到Overload的境地。可以簡單的想象一下,比如一個異步調用,當這個調用返回時只是表示請求被接收了,並不表示請求完成了,這樣一個調用可能只需要消耗一點點內存和一點點CPU,所以系統可以在很短的時間內完成大量的這種異步調用。但是,每個請求在執行的過程中可能要消耗大量的內存或者IO或者CPU,整個系統就不堪重負了。

 

整個更實在的例子吧:
假設Server最多能夠並行處理5個request,每個請求需要花費100ms的時間,所以系統的最大吞吐量爲50 request/sec。分別用兩個Client向Server發送請求。其中Client A是同步調用,Client B是異步消息調用。
如果兩個Client一開始都以50 request/sec(即每100ms發送5個request)的速度向server發送請求(對於Client A來說,它可以啓動5個thread,每個thread不斷的發送request,自然就可以達到要求的速度; 對於Client B來說,也可以啓動5個thread,每個thread執行一次調用之後就sleep 100ms,再執行下一次調用),由於沒有超過Server的最大負載能力,所以,無論是A還是B,都能夠將這個速度保持下去。


接下來,嘗試着增大Client的發送速度。Client A啓動6個thread,不斷的向Server發送request,因此可以認爲在一開始,Client A是以60 request/s的速度來發送request的;但是,如圖所示,在第一個100ms的中,A發送過來的6個request在Server端只能被處理5個,於是,在100ms這個時間點,A的6個thread只有5個的請求調用返回了,剩下的一個只能繼續等待,所以,在第二個100ms,只有5個thread發送了下一個request,於是,A的發送速度自然的下降爲50 request/s。以此類推,之後A的發送速度一直維持在50 request/s。(當然,和之前的5個thread相比還是有些區別的,能夠發現,每次發送的5個request其中有一個的延遲達到了200ms)

 

如果使用Client B,也是啓動6個thread,每個thread固定的以100ms的間隔執行異步請求調用(如下圖所示),在第一個100ms,發送了6個request,其中5個被處理,還有一個在等待下一個100ms被處理(假設Server滿足FIFO),在第二個100ms內,Client B又發送了6個request,但是系統首先需要將之前等待的request處理,於是只能再處理4個,所有,這次將有兩個request處於等待狀態。隨着時間的流逝,所有新發送的request都將處於等待狀態,因爲Server會一直忙於處理之前發送的request,並且,request的latency趨近於無限長。

以上的例子並不很嚴謹,實際系統的情況會更復雜和不可預測。但它能夠說明,如果不控制異步系統或者異步調用的調用速度,很容易的讓系統陷入“超載”的境地。


爲了避免這種情況的發生,一個實用的辦法就是在異步系統的前端掛上一個有限長度的隊列,所有接收的請求首先要被放入這個隊列中,而一旦隊列被填滿,那麼請求將不再被接受,在Client端會顯示異步調用失敗。這就好比是一個池子,當進水口的吞吐量大於出水口的吞吐量時,必須允許水可以從池子中溢出來,否則,池子是會爆炸的...

 

上面的例子其實還有另外一個角度的意義,即如何對系統性能進行測試?
我知道國內有很多的互聯網公司,當一個系統進行壓力測試時,就找幾臺機器,然後創建一些模擬客戶端線程/進程,每個線程不斷的向系統發送request並接收response,一如我們前面提及的同步機制。如果想加大壓力,就增加模擬線程的數量。
這其實是最常見的一種做法,它的好處在於整個測試相對簡單,並且很容易得到系統的Capability(只要計算一下模擬客戶端的發送速率就可以了)。而且,往往client發送request所消耗的資源要遠大於server處理request的消耗,所以,只要少量的客戶端進程就能夠使得系統達到它的capability。
但是,問題在於,用這種方式測試系統,很難使得系統處於Overload的狀態,也就沒法觀察系統在Overload的時候的表現。因爲正如前面所解釋的,當你增大模擬線程的數量後,很多線程其實會被阻塞住等待response,所以也就沒法發送新的request,因此,雖然request的latency會隨着模擬線程數量的增加而變大,但是Server其實一直處於滿負荷的狀態,卻並不會Overload。對於某些系統來說,在使用中可能很難Overload,但是對於很多其它的系統,Overload在實際運行中是常常碰見的情況。比如Web Server,有經驗性的數據表明,Web Server遭遇到的burst的峯值是它平均負載的8~10倍,所以,對於類似於Web Server這樣的系統,它在Overload情況下的表現是非常重要的一個性能指標,但這卻正是常用的測試方法所不能觀察到的。

 

-- END --

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章