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/CodeBenchmarkDoc