本次是对两款web框架做一次性能测试,这个测试做的很早,约在两个月前(也是actix-web4.0刚刚发布之后),目的是 比较有gc类web框架(springboot)与无gc类web框架(actix-web)的性能,分为带db查询与不带db查询这两种情况,简单探究下web框架的性能瓶颈在哪儿,仅此而已。
顺带说下,apache JMeter实在太垃圾...,这里不细说了诶~ 🙄️
测试工具
-c 表示并发数 | |
-n 每个并发执行请求的次数,总请求的次数 = 并发数 * 每个并发执行请求的次数 | |
-u 需要压测的地址 |
测试机器
window 10系统 8核32GB测试项目地址(springboot需自行添加代码)
springboot2(java)
@RestController | |
public class Echo2Controller { | |
@Autowired | |
public DB1SQLDao db1SQLDao; | |
// 带db资源的 | |
@GetMapping("/echo2") | |
public Map<String,Object> echo(){ | |
/* | |
<select id="findList2" resultType="java.util.Map"> | |
SELECT id,name,show_flag,create_date,code,parent_code from sys_menu limit 2 | |
</select> | |
*/ | |
List result = db1SQLDao.query("com.mee.xml1.tmp.findList2"); | |
Map<String, Object> res = ResultBuild.success("success"); | |
res.put("data",result); | |
return res; | |
} | |
// 不带DB资源的 | |
@GetMapping("/echo3") | |
public Map<String,Object> echo3(){ | |
/* | |
public static final Map<String,Object> SUCCESS = new HashMap<String,Object>(2,1){{ | |
put("status",1); | |
put("msg","成功"); | |
}}; | |
*/ | |
return ResultBuild.SUCCESS; | |
} | |
} |
actix-web4(rust)
// 仅json资源请求 | |
pub async fn echo() -> HttpResponse{ | |
return HttpResponse::Ok().json(ResultBuild::<&str>::success()); | |
} | |
// 带db的资源请求 | |
pub async fn sys_menu_list(/*req_body: String,*/db: web::Data<Pool>) -> HttpResponse{ | |
// async fn echo(/*req_body: String*/db: web::Data<Pool>) ->impl Responder { | |
// let mut conn=db.get().await.unwrap(); | |
// let rows=conn.query("select * from sys_menu ",&[]).await.unwrap(); | |
// // get参数可以是str,也可以是i32,获取第几个。但是必须要指明获取的类型 | |
// let sys_menus = menu_list(&db).await.expect("---error---"); | |
let sys_menu_list = menu_list(&db).await; | |
// HttpResponse::Ok().json(sys_menus) | |
return HttpResponse::Ok().json(ResultBuild::success_with_data(sys_menu_list)); | |
} | |
async fn menu_list(pool: &Pool) -> Vec<SysMenu> { | |
let client: Client = pool.get().await.expect("---error---"); | |
let stmt = client.prepare_cached("SELECT id,name,show_flag,create_date,code,parent_code from sys_menu limit 2").await.expect("--error2--"); | |
let rows = client.query(&stmt, &[]).await.expect("--error3"); | |
rows | |
.into_iter() | |
.map(|row| SysMenu { | |
id: row.get(0), | |
name: row.get(1), | |
show_flag: row.get(2), | |
create_date: row.get(3), | |
code: row.get(4), | |
parent_code: row.get(5), | |
}) | |
.collect() | |
} |
测试数据
CREATE TABLE "sys_menu" ( | |
"id" numeric(24) primary key, | |
"name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL, | |
"show_flag" int2 NOT NULL, | |
"create_date" timestamp(6) NOT NULL, | |
"create_by" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, | |
"code" varchar(8) COLLATE "pg_catalog"."default", | |
"parent_code" varchar(8) COLLATE "pg_catalog"."default" | |
); | |
COMMENT ON TABLE "public"."sys_menu" IS '系统::菜单表'; | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20010616453200802', '主页', 1, '2020-11-27 03:09:21.714105', 'sys', '01', NULL); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20010616513800803', '功能2', 1, '2020-11-27 03:09:24.25396', 'sys', '02', NULL); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20010616525500804', '功能1', 1, '2020-12-09 11:44:04.478717', 'sys', '03', NULL); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20010616545400805', '系统配置', 1, '2020-11-27 03:09:29.581216', 'sys', '04', NULL); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918550500800', '系统配置', 1, '2020-11-27 03:09:40.177621', 'sys', '0401', '04'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918561500801', '基础管理', 1, '2020-11-27 03:09:36.788131', 'sys', '0402', '04'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918572200802', '用户配置', 1, '2020-11-27 03:09:42.242687', 'sys', '040101', '0401'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918574400803', '菜单配置', 1, '2020-11-27 03:09:44.198666', 'sys', '040103', '0401'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918574400813', '角色分配', 1, '2020-11-27 03:09:47.713889', 'sys', '040102', '0401'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918581000804', '字典配置', 1, '2020-11-27 03:09:49.643454', 'sys', '040201', '0402'); | |
INSERT INTO "public"."sys_menu"("id", "name", "show_flag", "create_date", "create_by", "code", "parent_code") VALUES ('20082918584500805', '日志配置', 1, '2020-11-27 03:09:52.519771', 'sys', '040202', '0402'); |
目标资源通过数据库查询并序列化为json返回
go-stress-testing-win -c 8 -n 80000 -u http://127.0.0.1:8011/mee_auto/echo2 | |
go-stress-testing-win -c 8 -n 80000 -u http://127.0.0.1:8080/echo |
─────┬───────┬────────┬────────┬────────┬────────┬─────────┬─────────┬──────────┬─────────┬──────── | |
耗时 │ 并发数 │ 成功数 │ 失败数 │ qps │ 最长耗时 │ 最短耗时 │ 平均耗时 │ 下载字节 │ 字节每秒 │ 错误码 | |
─────┼───────┼───────┼────────┼─────────┼──────────┼──────────┼─────────┼─────────┼─────────┼──────── | |
163s│ 8│ 79453│ 0│ 505.33 │ 454.05 │ 6.45 │ 15.83 │ │ │200:79453 | |
164s│ 8│ 79911│ 0│ 505.41 │ 454.05 │ 6.45 │ 15.83 │ │ │200:79911 | |
164s│ 8│ 80000│ 0│ 505.43 │ 454.05 │ 6.45 │ 15.83 │ │ │200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 8 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 164.398 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
─────┬───────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬──────────┬──────── | |
耗时 │ 并发数│ 成功数 │ 失败数│ qps │ 最长耗时│ 最短耗时 │ 平均耗时 │ 下载字节│ 字节每秒 │ 错误码 | |
─────┼───────┼───────┼───────┼────────┼────────┼────────┼─────────┼────────┼─────────┼──────── | |
135s│ 8│ 79025│ 0│ 610.44│ 112.56│ 5.30│ 13.11 │22,601,150│ 167,412│200:79025 | |
136s│ 8│ 79617│ 0│ 610.49│ 112.56│ 5.30│ 13.10 │22,770,462│ 167,428│200:79617 | |
137s│ 8│ 80000│ 0│ 610.67│ 112.56│ 5.30│ 13.10 │22,880,000│ 167,155│200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 8 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 136.878 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
目标资源通过数据库查询并序列化为json返回
go-stress-testing-win -c 16 -n 80000 -u http://127.0.0.1:8011/mee_auto/echo2 | |
go-stress-testing-win -c 16 -n 80000 -u http://127.0.0.1:8080/echo |
─────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────┬──────── | |
耗时 │ 并发数 │ 成功数 │ 失败数 │ qps │ 最长耗时│ 最短耗时│ 平均耗时│ 下载字节│ 字节每秒│ 错误码 | |
─────┼───────┼───────┼───────┼────────┼────────┼────────┼────────┼────────┼────────┼──────── | |
146s│ 16│ 79294│ 0│ 558.06│ 553.22│ 8.20│ 28.67│ │ │200:79294 | |
147s│ 16│ 79861│ 0│ 558.22│ 553.22│ 8.20│ 28.66│ │ │200:79861 | |
147s│ 16│ 80000│ 0│ 558.07│ 553.22│ 8.20│ 28.67│ │ │200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 16 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 147.496 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
─────┬───────┬───────┬───────┬────────┬─────────┬─────────┬────────┬──────────┬─────────┬──────── | |
耗时│ 并发数 │ 成功数 │ 失败数│ qps │ 最长耗时 │最短耗时 │ 平均耗时 │ 下载字节 │ 字节每秒 │ 错误码 | |
─────┼───────┼───────┼───────┼────────┼─────────┼─────────┼────────┼──────────┼─────────┼──────── | |
139s│ 16│ 79468│ 0│ 584.20│ 259.02 │ 9.46 │ 27.39│22,727,848│ 163,508 │200:79468 | |
140s│ 16│ 79991│ 0│ 584.31│ 259.02 │ 8.97 │ 27.38│22,877,426│ 163,408 │200:79991 | |
140s│ 16│ 80000│ 0│ 584.33│ 259.02 │ 8.97 │ 27.38│22,880,000│ 163,248 │200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 16 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 140.155 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
目标资源仅仅为对象序列化为json返回
go-stress-testing-win -c 16 -n 160000 -u http://127.0.0.1:8011/mee_auto/echo3 | |
go-stress-testing-win -c 16 -n 160000 -u http://127.0.0.1:8080/echo3 |
─────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬─────────┬────────┬──────── | |
耗时│ 并发数 │ 成功数 │ 失败数 │ qps │ 最长耗时│ 最短耗时│ 平均耗时│ 下载字节 │ 字节每秒 │ 错误码 | |
─────┼───────┼───────┼────────┼────────┼────────┼────────┼─────────┼────────┼────────┼──────── | |
74s│ 16│ 157047│ 0 │ 2705.19│ 283.33│ 0.50│ 5.91 │ │ │200:157047 | |
75s│ 16│ 158698│ 0 │ 2696.52│ 283.33│ 0.50│ 5.93 │ │ │200:158698 | |
76s│ 16│ 160000│ 0 │ 2693.35│ 283.33│ 0.50│ 5.94 │ │ │200:160000 | |
************************* 结果 stat **************************** | |
处理协程数量: 16 | |
请求总数(并发数*请求数 -c * -n): 160000 总请求时间: 75.811 秒 successNum: 160000 failureNum: 0 | |
************************* 结果 end **************************** |
─────┬───────┬───────┬───────┬────────┬────────┬─────────┬────────┬──────────┬────────┬──────── | |
耗时│ 并发数 │ 成功数 │ 失败数│ qps │ 最长耗时│ 最短耗时 │ 平均耗时│ 下载字节 │ 字节每秒│ 错误码 | |
─────┼───────┼───────┼───────┼────────┼────────┼─────────┼────────┼──────────┼────────┼──────── | |
43s│ 16│ 155741│ 0│ 4620.61│ 113.40│ 0.64 │ 3.46│9,811,683 │ 228,177│200:155741 | |
44s│ 16│ 158948│ 0│ 4608.00│ 113.40│ 0.64 │ 3.47│10,013,724│ 227,583│200:158948 | |
44s│ 16│ 160000│ 0│ 4609.79│ 113.40│ 0.89 │ 3.47│10,080,000│ 227,478│200:160000 | |
************************* 结果 stat **************************** | |
处理协程数量: 16 | |
请求总数(并发数*请求数 -c * -n): 160000 总请求时间: 44.312 秒 successNum: 160000 failureNum: 0 | |
************************* 结果 end **************************** |
目标资源仅仅为对象序列化为json返回
go-stress-testing-win -c 8 -n 80000 -u http://127.0.0.1:8011/mee_auto/echo3 | |
go-stress-testing-win -c 8 -n 80000 -u http://127.0.0.1:8080/echo3 |
─────┬───────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬────────┬──────── | |
耗时 │ 并发数 │ 成功数 │失败数 │ qps │最长耗时│最短耗时 │平均耗时 │下载字节│字节每秒 │ 错误码 | |
─────┼───────┼───────┼───────┼────────┼────────┼────────┼─────────┼────────┼────────┼──────── | |
52s│ 8│ 76730│ 0│ 1820.31│ 253.83│ 0.30│ 4.39 │ │ │200:76730 | |
53s│ 8│ 78467│ 0│ 1826.48│ 253.83│ 0.30│ 4.38 │ │ │200:78467 | |
54s│ 8│ 80000│ 0│ 1834.15│ 253.83│ 0.30│ 4.36 │ │ │200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 8 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 53.885 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
──────┬───────┬───────┬────────┬───────┬─────────┬─────────┬─────────┬─────────┬────────┬──────── | |
耗时 │并发数 │ 成功数 │ 失败数 │ qps │ 最长耗时│ 最短耗时│ 平均耗时│ 下载字节 │ 字节每秒 │ 错误码 | |
─────┼───────┼───────┼────────┼────────┼─────────┼────────┼─────────┼──────────┼────────┼──────── | |
12s│ 8│ 69187│ 0 │ 7257.03│ 5.98 │ 1.00│ 1.10 │4,358,781 │ 363,207│200:69187 | |
13s│ 8│ 74735│ 0 │ 7232.76│ 5.98 │ 0.99│ 1.11 │4,708,305 │ 362,149│200:74735 | |
14s│ 8│ 80000│ 0 │ 7229.78│ 5.98 │ 0.00│ 1.11 │5,040,000 │ 361,557│200:80000 | |
************************* 结果 stat **************************** | |
处理协程数量: 8 | |
请求总数(并发数*请求数 -c * -n): 80000 总请求时间: 13.940 秒 successNum: 80000 failureNum: 0 | |
************************* 结果 end **************************** |
| 并发数 | 并发请求数 | 框架 | qps | 平均耗时 |
|---|---|---|---|---|
| 8 | 80000 | springboot | 505 | 15.83 |
| 8 | 80000 | actix-web | 610 | 13.10 |
| 16 | 80000 | springboot | 558 | 28.66 |
| 16 | 80000 | actix-web | 584 | 27.38 |
| 并发数 | 并发请求数 | 框架 | qps | 平均耗时 |
|---|---|---|---|---|
| 8 | 80000 | springboot | 1826 | 4.38 |
| 8 | 80000 | actix-web | 7232 | 1.11 |
| 16 | 160000 | springboot | 2696 | 5.93 |
| 16 | 160000 | actix-web | 4609 | 3.47 |
首先一个重要的前提是我的电脑是 i5 8核32GB 的配置
1.在带DB数据请求的下,不管是8个并发还是16个并发 springboot与actix-web两者的qps相距并不大,在cpu超载(16c)下平均耗时更多,据此可以得出 并发数与所在的机器配置是成正比的:硬件配置在其合理的并发下性能以及延迟是最优的
2.在不带DB的数据请求下,也显示了1的结论,同时也能看到随着cpu超载 延迟以及qps也会逐渐变得糟糕
3.对于springboot、actix-web这两款框架,无gc类语言在合适的并发&硬件配置下 性能(延迟、qps 、内存 、cpu利用率)相对与 gc类框架是存在优势的
4.对于web类框架(不管是gc类的还是非gc类的框架)他们的性能除了并发&硬件配置外 也取决于整个请求链路中性能最低的那一环:通过以上可以大致分析出性能一般是出在DB数据查询这一块儿,所以良好的DB架构及缓存配置可以有效提高应用的性能及硬件的利用率
需要的私我关键字【000】免费获取哦 注意关键字是:000
项目实战:

大型电商平台:

全套软件测试自动化测试教学视频

300G教程资料下载【视频教程+PPT+项目源码】

全套软件测试自动化测试大厂面经

python自动化测试++全套模板+性能测试


听说关注我并三连的铁汁都已经升职加薪暴富了哦!!!!