簡單效能測試:springboot-2.x vs actix-web-4.x benchmark

funnyZpC 發表於 2022-06-28
Spring

效能測試: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實在太垃圾...,這裡不細說了誒~ 🙄️

準備測試

準備測試程式碼及資料

  • 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個併發 springbootactix-web兩者的qps相距並不大,在cpu超載(16c)下平均耗時更多,據此可以得出 併發數與所在的機器配置是成正比的:硬體配置在其合理的併發下效能以及延遲是最優的

  • 2.在不帶DB的資料請求下,也顯示了1的結論,同時也能看到隨著cpu超載 延遲以及qps也會逐漸變得糟糕

  • 3.對於springboot、actix-web這兩款框架,無gc類語言在合適的併發&硬體配置下 效能(延遲qps記憶體cpu利用率)相對與 gc類框架是存在優勢的

  • 4.對於web類框架(不管是gc類的還是非gc類的框架)他們的效能除了併發&硬體配置外 也取決於整個請求鏈路中效能最低的那一環:通過以上可以大致分析出效能一般是出在DB資料查詢這一塊兒,所以良好的DB架構及快取配置可以有效提高應用的效能及硬體的利用率

    以上僅為個人測試所得結果,如有謬誤懇請指正~ 😊

相關文章