0

简单性能测试:springboot-2.x vs actix-web-4.x benchmark - funnyZpC

 1 year ago
source link: https://www.cnblogs.com/funnyzpc/p/15956465.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

性能测试: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需自行添加代码)

准备测试代码及数据

  • 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架构及缓存配置可以有效提高应用的性能及硬件的利用率

    以上仅为个人测试所得结果,如有谬误恳请指正~ 😊


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK