效能測試:springboot-2.x vs actix-web-4.x benchmark
轉載請註明出處 https://www.cnblogs.com/funnyzpc/p/15956465.html
前面
本次是對兩款web框架做一次效能測試,這個測試做的很早,約在兩個月前(也是actix-web4.0剛剛釋出之後),目的是 比較有gc類web框架(springboot
)與無gc類web框架(actix-web
)的效能,分為帶db查詢
與不帶db查詢
這兩種情況,簡單探究下web框架的效能瓶頸在哪兒,僅此而已。
順帶說下,apache JMeter
實在太垃圾...,這裡不細說了誒~ ?️
準備測試
-
測試工具
-c 表示併發數 -n 每個併發執行請求的次數,總請求的次數 = 併發數 * 每個併發執行請求的次數 -u 需要壓測的地址
-
測試機器
window 10
系統 8核32GB
-
測試專案地址(springboot需自行新增程式碼)
- springboot參考https://github.com/funnyzpc/mee-api
- actix-web參考https://github.com/funnyzpc/actix-web4_test
準備測試程式碼及資料
-
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');
1.1帶DB資源的請求 (8c-8w)
目標資源通過資料庫查詢並序列化為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
springboot (8c)
─────┬───────┬────────┬────────┬────────┬────────┬─────────┬─────────┬──────────┬─────────┬────────
耗時 │ 併發數 │ 成功數 │ 失敗數 │ 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 ****************************
actix-web (8c)
─────┬───────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬──────────┬────────
耗時 │ 併發數│ 成功數 │ 失敗數│ 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 ****************************
1.2帶DB資源的請求 (16c-8w)
目標資源通過資料庫查詢並序列化為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
springboot (16c)
─────┬───────┬───────┬────────┬────────┬────────┬────────┬────────┬────────┬────────┬────────
耗時 │ 併發數 │ 成功數 │ 失敗數 │ 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 ****************************
actix-web (16c)
─────┬───────┬───────┬───────┬────────┬─────────┬─────────┬────────┬──────────┬─────────┬────────
耗時│ 併發數 │ 成功數 │ 失敗數│ 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 ****************************
2.1不帶DB資源的請求 (16c-16w)
目標資源僅僅為物件序列化為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
springboot (16c)
─────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬─────────┬────────┬────────
耗時│ 併發數 │ 成功數 │ 失敗數 │ 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 ****************************
actix-web (16c)
─────┬───────┬───────┬───────┬────────┬────────┬─────────┬────────┬──────────┬────────┬────────
耗時│ 併發數 │ 成功數 │ 失敗數│ 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 ****************************
2.2不帶DB資源的請求 (8c-8w)
目標資源僅僅為物件序列化為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
springboot (8c)
─────┬───────┬───────┬───────┬────────┬────────┬────────┬─────────┬────────┬────────┬────────
耗時 │ 併發數 │ 成功數 │失敗數 │ 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 ****************************
actix-web (8c)
──────┬───────┬───────┬────────┬───────┬─────────┬─────────┬─────────┬─────────┬────────┬────────
耗時 │併發數 │ 成功數 │ 失敗數 │ 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 ****************************
請求一覽【帶DB資料請求】
併發數 | 併發請求數 | 框架 | 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 |
請求一覽【不帶DB資料請求(純程式碼json)】
併發數 | 併發請求數 | 框架 | 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架構及快取配置可以有效提高應用的效能及硬體的利用率
以上僅為個人測試所得結果,如有謬誤懇請指正~ ?