在前段時間對性能測試框架對比的文章中,我又重新學習了Java NIO
知識的學習,又發掘了一項「FunTester」優化,說幹就幹,現在就行動起來。
首先呢,先複習一下關於統計QPS中用到到一個請求模型。在之前的兩篇討論性能測試誤差的文章性能測試誤差分析文字版-上、性能測試誤差分析文字版-下中,我畫了一個簡單的請求時間模型。
計算模型
如圖所示,這是單個線程單個請求的耗時簡易模型,分成三部分:請求前(對應before
)、請求與響應(對應request and response
)和請求後(對應after
)。其中T
代表三個部分的總時間,rt
代表了請求與響應的時間。
Java NIO
Java NIO有兩種解釋:一種叫非阻塞IO(Non-blocking I/O),另一種也叫新的IO(New I/O),其實是同一個概念。NIO是一種基於通道和緩衝區的I/O方式,它可以使用Native函數庫直接分配堆外內存(區別於JVM的運行時數據區),然後通過一個存儲在java堆裏面的DirectByteBuffer對象作爲這塊內存的直接引用進行操作。這樣能在一些場景顯著提高性能,因爲避免了在Java堆和Native堆中來回複製數據。
以上內容摘要,我的理解也不十分透徹。PS:我更建議有能力的搜一搜,瞭解一下也是好的。
下面我分享一下Java NIO
在HTTP
協議接口測試中的應用。
緣由
在上圖第二部分中,請求和響應占據了整個部分。如果我們將這部分再細分,那麼可以分成三個部分:發出請求、等待響應、接收響應。Java NIO
在接口測試中的應用就在等待響應和接收響應這一部分。如果我們使用一種技術,將發出請求之後,等待響應和接收響應這個過程交給另外線程處理,又不影響兩者之間的關係,那麼我們就可以不斷地發出請求,提高客戶端性能而又不影響我們接收響應,進行業務驗證。
對於那些響應時間比較長的接口來說。這樣的處理結果能夠極大的提升客戶端發送請求的速率。對於線程數一定的情況下,由單個客戶端發起的壓力也會成倍的增加。經過本人在本地進行單線程模擬測試。(這個倍數大約在30倍左右。可見Java NIO
的性能提升有多強。當然在實際的更大壓力的性能測試中,這個倍數會降低很多。)
HttpClient應用
HttpAsyncClient則使用Java NIO的異步非阻塞事件驅動I/O模型,實現了真正意義的異步調用,使用HttpAsyncClient我們需要引入其專門的包
之前我有寫過文章:HTTP異步連接池和多線程實踐,只不過現在在看當時顯得特別的字呢,對於http client異步客戶端也有點兒理解不透徹,特別是對於callback函數的應用。
核心方法如下:
@Override
public Future<HttpResponse> execute(
final HttpUriRequest request,
final FutureCallback<HttpResponse> callback) {
return execute(request, HttpClientContext.create(), callback);
}
第一個是參數請求對象,第二個參數是回調函數。其中我之前常用的請求對象org.apache.http.client.methods.HttpRequestBase
,具體實現代碼摘要public abstract class HttpRequestBase extends AbstractExecutionAwareRequest implements HttpUriRequest, Configurable
。
下面是我經過一些資料的查證,重新寫了一下。Http client異步客戶端的使用方法的封裝。
不管不顧
這個方法只負責把請求發出去,至於響應一律不管。這裏據我查證,callback
如果傳null
的話,在處理響應的時候會直接釋放連接等相關資源。
/**
* 異步發送請求
*
* @param request
*/
public static void executeSync(HttpRequestBase request) {
ClientManage.httpAsyncClient.execute(request, null);
}
異步打印日誌
通過一個簡單的日誌打印功能實現FutureCallback
,來實現異步響應結果的解析和日誌打印功能。
/**
* 異步請求,打印日誌
*
* @param request
* @param response
*/
public static void executeSyncWithLog(HttpRequestBase request) {
ClientManage.httpAsyncClient.execute(request, logCallback);
}
/**
* 異步請求打印日誌的callback
*/
public static final FutureCallback<HttpResponse> logCallback = new FutureCallback<HttpResponse>() {
@Override
public void completed(HttpResponse httpResponse) {
HttpEntity entity = httpResponse.getEntity();
String content = getContent(entity);
logger.info("響應結果:{}", content);
}
@Override
public void failed(Exception e) {
logger.warn("響應失敗", e);
}
@Override
public void cancelled() {
logger.warn("取消執行");
}
};
異步解析響應
這裏我引入了第二個參數com.alibaba.fastjson.JSONObject
,用來保存解析響應,之所以加上這個,用來異步保存響應結果,用來業務驗證。
/**
* 異步請求,返回響應,引入第二個參數{@link JSONObject}
*
* @param request
* @param response
*/
public static void executeSyncWithResponse(HttpRequestBase request, JSONObject response) {
ClientManage.httpAsyncClient.execute(request, new FunTester(response));
}
/**
* 異步請求,異步解析響應的FutureCallback實現類
*/
private static class FunTester implements FutureCallback<HttpResponse> {
public FunTester(JSONObject response) {
this.response = response;
}
JSONObject response;
@Override
public void completed(HttpResponse result) {
HttpEntity entity = result.getEntity();
String content = getContent(entity);
response = JSON.parseObject(content);
}
@Override
public void failed(Exception e) {
logger.warn("響應失敗", e);
}
@Override
public void cancelled() {
logger.warn("取消執行");
}
}
-
httpAsyncClient
和HttpClient
性能對比,以及這三個方法的性能比較。後續我會進行對比測試。原因是本地服務響應太快,無法體現差異。
❝「Have Fun ~ Tester !」
❞
-
FunTester測試框架架構圖初探 -
10萬QPS,K6、Gatling和FunTester終極對決! -
單機12萬QPS——FunTester復仇記 -
超萬字回顧FunTester的前世今生 -
生產環境中進行自動化測試 -
編寫測試用例的技巧 -
成爲自動化測試的7種技能 -
物聯網測試 -
測試爲何會錯過Bug -
Selenium自動化最佳實踐技巧(上) -
Selenium自動化最佳實踐技巧(中) -
Selenium自動化最佳實踐技巧(下) -
Socket接口異步驗證實踐 -
Selenium 4以後,再不相見的API
「點擊閱讀閱文,查看FunTester歷史原創集合」
本文分享自微信公衆號 - FunTester(NuclearTester)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。