CodeBenchmark之壓力測試詳解
CodeBenchmark
是一款高效能視覺化的併發測試元件,通過元件可以對任意邏輯程式碼或服務進行併發測試;元件最終通過視覺化的方式來顯示測試結果,在測試結果中可以看到具體的併發情況和處理延時的分佈。元件不僅可以對單個邏輯或服務進行併發測試,還可以同時對多個邏輯程式碼用例進行不同併發分組壓測,最終顯示它們之間的效能差異和不同併發下的最優結果。接下來介紹如何使用這一元件對邏輯程式碼或服務進行併發測試。
構建測試專案
可以通過vs
或vscode
構建一個控制檯專案然後引用元件(引用最新版本的BeetleX.CodeBenchmark
)
Install-Package BeetleX.CodeBenchmark -Version 1.0.8
實現一個HTTP壓測
引用元件後就可以編寫具體的測試用例,測試用例編寫必須符合元件測試要求,所以需要實現一個介面來編寫測試程式碼,介面描述如下:
public interface IExample:IDisposable { void Initialize(Benchmark benchmark); Task Execute(); }
HTTP壓測邏輯程式碼
[System.ComponentModel.Category("TCP")] class HttpGet : IExample { public void Dispose() { } public async Task Execute() { var result = await _httpHandler.json(); } public void Initialize(Benchmark benchmark) { if(_httpApi==null) { _httpApi = new BeetleX.Http.Clients.HttpClusterApi(); _httpApi.DefaultNode.Add("http://192.168.2.19:8080"); _httpHandler = _httpApi.Create<IHttpHandler>(); } } static BeetleX.Http.Clients.HttpClusterApi _httpApi; static IHttpHandler _httpHandler; [BeetleX.Http.Clients.FormUrlFormater] public interface IHttpHandler { // http://host/json Task<string> json(); } }
在併發例項初始化的時候建立一個請求http
請求物件,HttpClusterApi
是一個執行緒安全物件所以只需要靜態化構建一個即可;元件會針對第一個併發來構建一個例項。
啟動壓測
當測試用例寫好後就需要進行測試,通過以下簡單程式碼即可以開啟測試管理
Benchmark benchmark = new Benchmark(); benchmark.Register(typeof(Program).Assembly); benchmark.Start();//在本地開啟管理服務,服務埠默信是9090 if(Environment.OSVersion.Platform== PlatformID.Win32NT) benchmark.OpenWeb();
程式碼中做了一下判斷,如果當前系統是windows
則自動開啟瀏覽器訪問服務(由於服務是基於vue實現,會存在一些舊瀏覽器相容問題,建議使用新版瀏覽器)。
管理和測試
當服務開啟後就可以通過瀏覽器管理測試用例,具體介面如下:
在管理介面中你只需要選擇測試用例和新增併發測試即可以進行壓測,以下是開啟10個併發並執行10秒的測試情況:
執行後能看到併發完成的數量和平均的RPS
,點選測試的用例還能看到延時分佈,可以知道大部分處理分佈在那個時間區域。
不同併發對比
很多時候需要對一個服務進行不同併發的測試,這樣可以觀察服務在那個併發量下的最併發處理能力;元件支援對同時新增多個測試併發組並進行測試和結果對比。
在這個硬體和測試場景之下,顯然是8併發的測力測試結果最高
通這個測試就可以針對服務情況來規劃併發控制設計。接下來換個環境試下同樣的測試
通過工具可以很快就能測出不同環境下最優的併發處理效果
多邏輯併發能效能對比
元件也支援多用例壓測對比,只需要在測試的時候選擇多個測試用例即可。接下來簡單地測試一下不同json
元件序列化的效能對比。 測試分別有Newtonsoft.Json
,Utf8Json
,SwifterJson
和spanJson
.相應程式碼如下:
-
Newtonsoft.Json
[System.ComponentModel.Category("Serializer-Stream")] class Newtonsoft_Stream : CodeBenchmark.IExample { public void Dispose() { } public Task Execute() { memoryStream.Position = 0; var users = User.List(10); jsonSerializer.Serialize(jsonTextWriter, users); jsonTextWriter.Flush(); return Task.CompletedTask; } private System.IO.MemoryStream memoryStream; private System.IO.StreamWriter streamWriter; private Newtonsoft.Json.JsonSerializer jsonSerializer; private Newtonsoft.Json.JsonTextWriter jsonTextWriter; public void Initialize(Benchmark benchmark) { memoryStream = new System.IO.MemoryStream(); jsonSerializer = new Newtonsoft.Json.JsonSerializer(); streamWriter = new StreamWriter(memoryStream); jsonTextWriter = new Newtonsoft.Json.JsonTextWriter(streamWriter); } }
-
Utf8Json
[System.ComponentModel.Category("Serializer-Stream")] class Utf8Json_Stream : CodeBenchmark.IExample { public void Dispose() { } public async Task Execute() { MemoryStream.Position = 0; var users = User.List(10); await Utf8Json.JsonSerializer.SerializeAsync<List<User>>(MemoryStream, users); TextWriter.Flush(); } private System.IO.MemoryStream MemoryStream = new System.IO.MemoryStream(); private System.IO.TextWriter TextWriter; public void Initialize(Benchmark benchmark) { TextWriter = new System.IO.StreamWriter(MemoryStream, Encoding.UTF8); } }
-
SwifterJson
[System.ComponentModel.Category("Serializer-Stream")] class Swifter_Stream : CodeBenchmark.IExample { public void Dispose() { } public async Task Execute() { MemoryStream.Position = 0; var users = User.List(10); await Swifter.Json.JsonFormatter.SerializeObjectAsync<List<User>>(users, TextWriter); TextWriter.Flush(); } private System.IO.MemoryStream MemoryStream = new System.IO.MemoryStream(); private System.IO.TextWriter TextWriter; public void Initialize(Benchmark benchmark) { TextWriter = new System.IO.StreamWriter(MemoryStream, Encoding.UTF8); } }
-
SpanJson
[System.ComponentModel.Category("Serializer-Stream")] class Span_Stream : CodeBenchmark.IExample { public void Dispose() { } public async Task Execute() { var users = User.List(10); MemoryStream.Position = 0; await SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeAsync(users, MemoryStream); } private System.IO.MemoryStream MemoryStream = new System.IO.MemoryStream(); public void Initialize(Benchmark benchmark) { } }
接下來對這幾個邏輯進行2,4,8,16和32的併發壓測(注意:在這裡提醒一下,如果是壓測記憶體運算資料的情況併發數最好不要超過CPU的邏輯核數,否則會導致元件計數Timer可能沒機會觸發或觸發延時)
到這裡CodeBenchmark
的使用就講解完成,如果有興趣可以關注https://github.com/IKende/CodeBenchmar