转载请注明出处 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');
目标资源通过数据库查询并序列化为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架构及缓存配置可以有效提高应用的性能及硬件的利用率
以上仅为个人测试所得结果,如有谬误恳请指正~ ?
我正在使用Ruby/Mechanize编写一个“自动填写表格”应用程序。它几乎可以工作。我可以使用精彩CharlesWeb代理以查看服务器和我的Firefox浏览器之间的交换。现在我想使用Charles查看服务器和我的应用程序之间的交换。Charles在端口8888上代理。假设服务器位于https://my.host.com。.一件不起作用的事情是:@agent||=Mechanize.newdo|agent|agent.set_proxy("my.host.com",8888)end这会导致Net::HTTP::Persistent::Error:...lib/net/http/pe
Asitcurrentlystands,thisquestionisnotagoodfitforourQ&Aformat.Weexpectanswerstobesupportedbyfacts,references,orexpertise,butthisquestionwilllikelysolicitdebate,arguments,polling,orextendeddiscussion.Ifyoufeelthatthisquestioncanbeimprovedandpossiblyreopened,visitthehelpcenter提供指导。11年前关闭。我是一位精通HTML
我目前正在为一个新网站设计版本化的API。我了解如何为路由命名空间,但我一直坚持在模型中实现版本化方法的最佳方式。下面的代码示例使用的是rails框架,但是事情的原理在大多数web框架之间应该是一致的。目前的路线看起来像这样:MyApp::Application.routes.drawdonamespace:apidonamespace:v1doresources:products,:only=>[:index,:show]endendend和Controller:classApi::V1::ProductsController很明显,我们只是在此处公开Product上可用的属性,如果
我正在尝试使用ruby来使用Sharepoint网络服务。我基本上已经放弃尝试使用NTLM进行身份验证,并暂时将Sharepoint服务器更改为使用基本身份验证。我已成功使用soap4r获得WSDL,但在尝试使用实际Web服务调用时仍然无法进行身份验证。有没有人有过让ruby和Sharepoint对话的经验? 最佳答案 我是个新手。但经过很多时间并在更多经验编码人员的帮助下,我能够让ruby与Sharepoint2010一起工作。下面的代码需要“ntlm/mechanize”gem。我已经能够使用列表GUID和ListV
2022年10月21日星期五【数据指标】加密货币总市值:$0.95万亿BTC市值占比:38.51%恐慌贪婪指数:23极度恐慌 【今日快讯】1、【政讯】1.1.1、美联储布拉德:市场预期美联储11月会加息75个基点1.1.2、美联储哈克:将维持加息一段时间1.2、美国10年期国债收益率触及4.197%,为2008年6月以来最高1.3、法国数字转型部长:政府将专注于DeFi和Web31.4、巴西ATM机将于11月3日起支持USDT1.5、美众议院副议长将于11月初加入a16zCrypto担任政府事务主管1.6、香港数字资产托管机构FirstDigitalTrust首席执行官:香港仍是安全
如果您希望在Spring中启用定时任务功能,则需要在主类上添加 @EnableScheduling 注解。这样Spring才会扫描 @Scheduled 注解并执行定时任务。在大多数情况下,只需要在主类上添加 @EnableScheduling 注解即可,不需要在Service层或其他类中再次添加。以下是一个示例,演示如何在SpringBoot中启用定时任务功能:@SpringBootApplication@EnableSchedulingpublicclassApplication{publicstaticvoidmain(String[]args){SpringApplication.ru
WAF可以对网站进行扫描,识别API漏洞。API安全如何设置API安全_Web应用防火墙-阿里云帮助中心API安全如何划分API业务用途?登录认证手机验证码认证数据保存数据查询数据导出数据分享数据更新数据删除数据增加下线注销信息发送信息认证邮件信息发送邮箱验证码认证账号密码认证账号注册API安全支持检测哪些敏感数据?敏感数据级别敏感数据类型非敏感数据(N)不涉及。特级敏感数据(L0)与一级敏感数据(L1)或二级敏感数据(L2)相同。单次响应中一级敏感数据(L1)较多时,升级为特级敏感数据(L0)。单次响应中二级敏感数据(L2)较多时,升级为一级敏感数据(L1)或特级敏感数据(L0)。一级敏感数
软件特点部署后能通过浏览器查看线上日志。支持Linux、Windows服务器。采用随机读取的方式,支持大文件的读取。支持实时打印新增的日志(类终端)。支持日志搜索。使用手册基本页面配置路径配置日志所在的目录,配置后按回车键生效,下拉框选择日志名称。选择日志后点击生效,即可加载日志。windows路径E:\java\project\log-view\logslinux路径/usr/local/XX历史模式历史模式下,不会读取新增的日志。针对历史文件可以分页读取,配置分页大小、跳转。历史模式下,支持根据关键词搜索。目前搜索引擎使用的是jdk自带类库,搜索速度相对较低,优点是比较简单。2G日志全文搜
1.依赖导入org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-validation2.validation常用注解@Null被注释的元素必须为null@NotNull被注释的元素不能为null,可以为空字符串@AssertTrue被注释的元素必须为true@AssertFalse被注释的元素必须为false@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值@D
我正在使用RubyonRails3,我正在尝试实现API以从Web服务检索帐户信息。也就是说,我想连接到具有Account类的Web服务并从show获取信息。在URIhttp:///accounts/1处路由的操作.此时,在网络服务中accounts_controller.rb我有的文件:classAccountsController@account.to_json}endendend现在我需要一些关于连接到网络服务的建议。在客户端应用程序中,我应该有一个HTTPGET请求,但这是我的问题:连接到发出HTTP请求的Web服务的“最佳”方法是什么?客户端应用程序中的这段代码有效:url=