.netcore - gRPC vs WebApi 耗时比较
测试环境
gRPC & WebApi 服务运行环境
项目 | 值 |
---|---|
CPU | 1 |
内存 | 2GB |
操作系统 | ubuntu 虚拟机 |
软件 | docker |
运行时 | .NET Core 3.0 |
测试场景
使用不同gRPC和WebApi实现一个UserService,提供SayHi的接口,接收一个字符串参数,返回对这个字符串的简单拼接后的结果,进行单连接/多连接循环调用、并行调用,记录最小耗时、最大耗时、平均耗时。
我非常认同内存、CPU占用很重要,但水平有限,这里不做测试了
除了时间,内存占用实际也是非常非常重要、但容易被人忽略的性能指标。大家都以为“内存不值钱”,但——
- 一旦访问量大,内存就会瞬间上涨,导致频繁
GC
,导致性能下降;- 内存高也会导致服务器分页,这时性能就会急剧下降;
- 吞吐量下降会导致队列排满,此时服务器就会报503等错误,客户就发现服务器“宕机了”。
(提示:除非你的客户真的愿意多花钱再升级一下服务器,否则不要提“内存不值钱”。)
摘抄自.net骚操作: https://www.cnblogs.com/sdflysha/p/20190824-dotnet-excel-compare.html
起初设计的是采用微软官方推荐的方式实现gRPC服务,但这种方式实测下来比WebApi还慢,因此增加了采用gRPC官方提供的实现方式进行对比。
gRPC官方提供的实现方式: https://github.com/grpc/grpc/tree/master/src/csharp
.netcore3.0推荐的实现方式是用VS2019创建gRPC项目时直接使用gRPC模版创建,这种情况下实际创建的是一个Web项目,并且自动引用了Grpc.AspNetCore包,这个包里面做了一些封装且引用了Google.Protobuf、Grpc.Tools、Grpc.Core.Api等
最终的测试项目结构如下
- GrpcService:基于.netcore3.0推荐的gRPC实现方式,实际是一个Web项目
- GrpcServiceConsoleApp:基于gRPC官方提供的实现方式,是一个控制台应用程序
- WebApi:基于.netcore3.0的WebApi项目
- Test:用于测试调用的客户端,是一个控制台应用程序
测试代码在此: https://github.com/RiccoYuan/gRPC.NetCoreTest
测试结果
1000次For循环调用,循环里面每次创建新的连接
项目/耗时(毫秒) | 最小耗时 | 最大耗时 | |
---|---|---|---|
GrpcService | 13.113 | 9 | 738 |
GrpcServiceConsoleApp | 2.854 | 1 | 176 |
WebApi | 6.331 | 5 | 56 |
1000次For循环调用,只在循环外面创建一次连接
项目/耗时(毫秒) | 平均耗时 | 最小耗时 | 最大耗时 |
---|---|---|---|
GrpcService | 5.649 | 4 | 18 |
GrpcServiceConsoleApp | 2.178 | 1 | 131 |
WebApi | 1.155 | 1 | 7 |
1000次Parallel并行调用,这里只测试了每次创建新的连接的情况
项目/耗时(毫秒) | 平均耗时 | 最小耗时 | 最大耗时 |
---|---|---|---|
GrpcService | 13296.676 | 10875 | 17642 |
GrpcServiceConsoleApp | 2350.708 | 471 | 3652 |
WebApi | 8128.383 | 943 | 10645 |
手动进行了多次测试,结果相对而言都差不多,得出以下结论:
- 从客户端建立连接到拿到请求响应,在单线程循环调用和多线程并行调用,gRPC的耗时都比WebApi快3倍左右,符合预期。
在客户端只建立单个连接的情况下,WebApi比gRPC更快,这里面的原因我还不知道。
上述的任何场景下,gRPC官方提供的实现方式比.netcore3.0推荐的gRPC实现方式快。
暂且认为,gRPC官方提供的实现方式
优于WebApi
优于.netcore3.0推荐的gRPC实现方式
为什么.netcore3.0推荐的gRPC实现方式会慢这么多,可能是封装的代码还需要优化吧,相信官方在后面的版本会修复这个问题。
原文地址:https://www.cnblogs.com/ricco/p/11730273.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法