ASP.NET Core 使用 gRPC 初探

(RPC通讯示意图)

为什么突然说到gRPC呢,其实以前就想说一说这个东西,也想尝试使用一下,一直没有机会,一直看我公众号的小伙伴肯定都知道,这几天一直在录制一个《eShopOnContainer微服务架构》系列,现在已经是8期了,里边涵盖了使用ASP.NETCore开发微服务的常用的基本的知识技能,具体的你可以看我的视频就行,B站也同步更新。

既然要说到了微服务,那肯定就离不开服务间调用,自然而然的就联系到了常用的一个框架——gRPC了,那今天就简单的说一说这个框架,也算是一个刚入门的,比较简单,后边我也会持续跟进讲解。

 划 

 重 

 点 

gRPC是什么?

用官网的一句话就是:A high-performance, open-source universal RPC framework。

要说gRPC,那就先说下什么的RPC框架,所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。

gRPC就是一个由Google开源的,跨语言的,高性能的远程过程调用(RPC)框架。gRPC使客户端和服务端应用程序可以透明地进行通信,并简化了连接系统的构建。它使用HTTP/2作为通信协议,使用 Protocol Buffers 作为序列化协议。

可能第一次看到这种通信框架比较陌生,介绍的也比较官方和抽象,这里说一下另一个常用的服务间通讯的方案,你可能就明白了,那就是RESTFul风格的API,想必每个人都用过RestfulAPI吧,这里就先简单说下RestfulAPI,如果这个还不是很理解的话,建议死记硬背。

1、REST,即Representational State Transfer的缩写。直接翻译的意思是"表现层状态转化"。
2、它是一种互联网应用程序的API设计理念:URL定位资源,用HTTP动词(GET,POST,DELETE,PUT,DETC)描述操作,比如只需要知道/api/blog,你就知道了他的常见的CURD多种操作。

3、简单来说就是url地址中只包含名词表示资源,使用http动词表示动作进行操作资源,软件和网络这两个领域一定程度上结合起来

4、之所以灵活,是因为他很少参与业务逻辑,只定义资源操作


看完了RestfulAPI,你应该就能明白gRPC是干什么的了吧。

那两者有什么区别呢,平时在前后端分离或者移动端需要后端api的场景下,经常使用Restful丰富的API,既然大家已经习惯并熟悉了Restful,为何还用gRPC呢?

PS:下边的内容我基本是摘抄于官网和网络,文末有参考连接,今天主要是介绍下如何操作代码,文字讲解不是重点。

为什么要使用gRPC?

问题:既然是server/client模型,那么我们直接用restful api不是也可以满足吗,为什么还需要RPC呢?

我这里简单说明下优缺点和比较,说说到底使用gRPC有什么好处。

gRPC 和 Restful API

gRPC和Restful API都提供了一套通信机制,用于server/client模型通信,而且它们都使用http作为底层的传输协议(严格地说, gRPC使用的http2.0,而Restful api则不一定)。

不过gRPC还是有些特有的优势,如下:

1、gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。

2、通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。

3、gRPC可以方便地支持流式通信.

场景与好处????

1、需要对接口进行严格约束的情况。

比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。

2、对于性能有更高要求的轻量级微服务。

有时我们的服务需要传递大量的数据,而又不希望影响到我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。

同时,更适应于网络受限的环境,使用 Protocol Buffers二进制序列化消息,该序列化始终小于等效的JSON消息,对网络带宽需求比JSON小。

 

3、需要对接多种语言的微服务的情况。

比如我们公司的项目,有JAVA组,有Python组,或者.NETCore组别,每个组当然负责各自独立的子服务部分,那就需用用到不同语言之间的服务调用问题,不希望出现兼容性问题。这个时候就用到了gRPC了,它协定优先 API 开发,默认使用协议缓冲区,允许与语言无关的实现。可用于多种语言的工具,以生成强类型服务器和客户端。gRPC工具支持所有流行的开发语言,使gRPC成为多语言开发环境的理想选择。

4、需要处理流式处理请求或响应的点对点实时服务

gRPC用更小的网络带宽,又支持客户端、服务器和双向流式处理调用,更好的帮助处理流式请求。

(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的Restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)

也并不是十全十美的????

任何开发工具或者项目框架都不是十全十美的,就算是K8s、微服务或者DDD这么火热的技术也并不是无脑就上的,gRPC框架也有一定的弊端,或者至少是某些场景下是不适合的:

1、浏览器可访问的API。

 浏览器不完全支持gRPC。虽然gRPC-Web可以提供浏览器支持,但是它有局限性,引入了服务器代理

2、广播实时通信

gRPC支持通过流进行实时通信,但不存在向已注册连接广播消息的概念

3、进程间通信

进程必须承载HTTP/2才能接受传入的gRPC调用,对于Windows,进程间通信管道是一种更快速的方法。

如何.NETCore上使用gRPC?

关于如何在ASP.NETCore上使用gRPC,这里有两种方法,第一是直接创建gRPC模板项目,第二个就是在在ASP.NETCore项目上创建gRPC服务。其实这两个原理和操作流程都是差不多的,我这里都说一下吧。

通过模板创建gRPC服务

打开VS2019(版本至少16.3+),新建项目,搜索"gRPC",就能看到一个选项,

点击下一步,填写好项目名称和项目地址以后,点击创建,

然后可以看到NetCore版本是3.1,然后不勾选Docker,点击创建。

等待新建好项目,就可以看到默认的文件是这样的,其实和我们创建ASP.NETCore项目是很相似的,如果说真的不一样,就是依赖包和多了一个Protos的文件夹,那下边我们来一一看看都是怎么作用的:

1、依赖包

Grpc.AspNetCore是gRPC结合ASP.NETCore封装的一个类库,其中很重要的是下边的两个依赖包,第一个就是Protobuf,第二个就是Tools,从名字上应该都能大概猜出来是干啥的,肯定有一个是解析protobuf文件的,一个是工具包,负责一些操作的。

2、Protos文件夹

在文章的开头我们已经说过了,gRPC很重要的一点,就是在请求和相应的的时候需要用到一个.proto的文件,用来定义服务和提供参数已经响应的参数。

默认的内容是这样的:

  // 语法结构,使用pb3syntax = "proto3";// 定义命名空间,一般是项目名或者解决方案名option csharp_namespace = "GrpcService1";// 定义服务的包package greet;// 定义具体的服务service Greeter {// 定义某一个方法API,格式是:rpc 方法名(请求参数对象名) returns(返回参数对象名)rpc SayHello (HelloRequest) returns (HelloReply);}// 定义请求的对象名message HelloRequest {// 有一个属性字段是namestring name = 1;}// 定义返回的对象名message HelloReply {// 有一个返回的字段是messagestring message = 1;}

可以看到虽然是扩展名是.proto的文件,但是语法结构很像一个.cs文件,语法上也类似,当然只不过是类似,具体的意思我已经在上边注释了,你看看就能明白。

你可能会好奇,那我定义好了这一个文件,怎么来使用呢,别着急,分成两步,咱们先说第二步定义具体服务,第一步先卖个关子。

3、GreeterService服务

上边我们定义好了proto文件,下边就需要针对这个配置,设计服务了,因为proto仅仅是定义了服务,还没有具体的内容,那很简单,就直接看代码吧。

 /// <summary>/// 根据.proto定义具体的服务/// GreeterService可以任意定义/// Greeter.GreeterBase 根据.proto文件中定义的规则来/// </summary>public class GreeterService : Greeter.GreeterBase{// 和ASP.NETCore一样,可以使用依赖注入和服务private readonly ILogger<GreeterService> _logger;public GreeterService(ILogger<GreeterService> logger){_logger = logger;}/// <summary>/// 重写 设计对应的多个接口/// 一般都是异步处理/// </summary>/// <param name="request"></param>/// <param name="context"></param>/// <returns></returns>public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context){return Task.FromResult(new HelloReply{Message = "Hello " + request.Name});}}

我也同样的把注释都写上了,其实内容都是很简单的,我们都已经用了ASPNETCore这么久了,肯定都一样都能看明白,有两个问题肯定你会问:

第一、定义服务我明白,但是继承的父类Greeter.GreeterBase是如何处理的呢?

这个就是我第二步说完.proto文件的时候卖的那个关子,我们定义好了.proto文件后,系统会自动给我们创建生成服务、客户端和消息(表示传递的数据)的C# Class,但是需要一个操作:

右键项目,编辑项目文件,可以看到有一个配置:

  <ItemGroup><Protobuf Include="Protos\greet.proto" GrpcServices="Server" /></ItemGroup>

这个是官方默认模板已经创建好的,是一个Server类型的服务,Include对应的文件,然后项目就能自动给我们创建好了父类,你可以从obj文件夹看到:

这个时候,就可以继承了。

第二、如何重写对应的方法呢?

很简单,直接针对当前的类型,alt+enter,在智能提示里,找到重写,就可以看到要重写的接口了:

4、appsettings.json

注意这里别之前不一样的地方,就是定义了一个节点:

"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"}}

在上边我们说过,gRPC 需要 HTTP/2。 适用于 ASP.NET Core 的 gRPC 验证 HttpRequest.Protocol 为 HTTP/2。

Kestrel 在大多数新式操作系统上支持 HTTP/2。默认情况下,Kestrel 终结点配置为支持 HTTP/1.1 和 HTTP/2 连接。

5、Startup.cs

其他的文件内容都类似,我就不多说了,我们都知道,要用一个服务,就需要注册这个服务,那就肯定需要是Startup里,

 // 注册grpc服务services.AddGrpc();// 在结点路由里配置指定的服务app.UseEndpoints(endpoints =>{endpoints.MapGrpcService<GreeterService>();endpoints.MapGet("/", async context =>{await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");});});

项目启动,

可以看到,只有https安全协议的,因为上边已经说过了使用gRPC必须是http/2的,同样也是需要https安全协议的。

到这里就没有问题了,说完了系统默认模板创建的方案,那现在我们不用这个方案,尝试一下,如果已经创建好了一个NetCore的API项目,比如我的Blog.Core,如何在这个基础上,创建gRPC服务呢?

基于ASP.NETCore项目创建

因为上边我们已经讲完了对应的内容和注意事项,为了篇幅不罗嗦,我就直接创建,看看是否真的可以:

还是在当然解决方案,创建一个netcore的api项目,然后添加三个nuget包:

<PackageReference Include="Google.Protobuf" Version="3.11.2" />
<PackageReference Include="Grpc.AspNetCore.Server" Version="2.25.0" />
<PackageReference Include="Grpc.Tools" Version="2.25.0" PrivateAssets="All" />  

接着添加helloworld.proto文件,配置.csproj项目配置,包含当前的.proto文件,创建HelloWorldservice.cs服务类,继承刚刚创建好的父类Hello.HelloBase,最后,注册服务,配置中间件,相应的操作可以看下边的视频:

现在我们已经定义了好了server端的服务,那如何发起调用呢,需要一个client客户端。

如何发起调用?

1、创建一个netcore的控制台

还是在该解决方案中,添加一个控制台项目

然后添加三个依赖包:

<ItemGroup><PackageReference Include="Google.Protobuf" Version="3.13.0" /><PackageReference Include="Grpc.Net.Client" Version="2.32.0" /><PackageReference Include="Grpc.Tools" Version="2.33.1"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference>
</ItemGroup>

注意,这里我们并没有添加其他的项目引用!

2、把Hello.proto拷贝到控制台

这个很简单,只需要直接把文件夹和文件直接拖动过去就行了。

然后配置下.csproj文件,修改下gprc的服务类型,一定是client:

<ItemGroup><Protobuf Include="Proto\helloworld.proto" GrpcServices="Client" />
</ItemGroup>

3、发起调用

我这里就直接写代码了

 class Program{static async System.Threading.Tasks.Task Main(string[] args){// 创建通道var channel = GrpcChannel.ForAddress("https://localhost:5001");// 发起客户端调用var client = new Hello.HelloClient(channel);// api请求,传递参数var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });Console.WriteLine("Greeting: " + response.Message);}}

大概意思就是这样的,应该能够看懂的。

运行我们的gRPC服务,也就是运行core的webapi程序,然后运行客户端控制台:

看到没有,我们并没有在控制台去引用我们的gRPC服务端的代码,只需要一个.proto文件,就能够像调用方法一样,去调用其他服务端项目的服务,这就是很大的直观上的好处。

当然好处还有很多的,比如什么是流式,如何实现服务间调用,如何网关配置等等等等,咱们下次再见吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307197.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

源码都没调试过,怎么能说熟悉 redis 呢?

一&#xff1a;背景 1. 讲故事记得在很久之前给初学的朋友们录制 redis 视频课程&#xff0c;当时结合了不少源码进行解读&#xff0c;自以为讲的还算可以&#xff0c;但还是有一个非常核心的点没被分享到&#xff0c;那就是源码级调试&#xff0c; 对&#xff0c;读源码还远远…

算法 - DFS/BFS

写DFS函数的时候首先确定当前位置是否已经加入路径 DFS函数大概率会传递“位置信息”&#xff0c;根据位置信息获取下一步的选择&#xff0c;&#xff08;大部分是在循环中&#xff09;选择、执行、回退 在哪做选择&#xff0c;就在哪退出选择&#xff0c;参考题9 def DFS()…

你想象中的Task后续,很简单?

【导读】前不久&#xff0c;写过一篇关于Task的简短文章&#xff0c;通过评论和转载得到好评&#xff0c;刚好我昨晚又写了一篇实现简单的消息队列也提到了Task&#xff0c;难道不应该是看具体执行什么操作&#xff0c;再考虑最佳方案&#xff1f;本文我们再次通过简短内容谈谈…

算法 - 动态规划

动态规划是一种自底向上的算法&#xff0c;通常用于解决最大、最小等最值问题。 能使用动态规划解决的问题&#xff0c;一定具备&#xff1a; 重叠子问题&#xff1a;和暴力搜索不同&#xff0c;需要记录子问题的解&#xff0c;避免重复求解&#xff08;剪枝&#xff09;最优…

5G在工业互联网应用的机遇与挑战

移动通讯经过十年一代的发展&#xff0c;已经从1G发展到了5G&#xff0c;峰值速率实现十年千倍的增长&#xff0c;1G到4G是面向个人的&#xff0c;而5G是面向产业互联网和智慧城市服务。5G是一个颠覆性的技术&#xff0c;低时延&#xff08;每秒钟下载一部高清电影&#xff09;…

算法 - 前缀和

记录在做hot100时遇到的前缀和的题目。 目前见过的题目&#xff0c;都是前缀和结合其它的方法一起使用&#xff1a;用于求取一段连续路径的和&#xff08;最大值/最小值/目标出现次数&#xff09;。 需要注意的是&#xff0c;前缀和的判定方法是node2.val-node1.val target&am…

[C#.NET 拾遗补漏]10:理解 volatile 关键字

要理解 C# 中的 volatile 关键字&#xff0c;就要先知道编译器背后的一个基本优化原理。比如对于下面这段代码&#xff1a;public class Example {public int x;public void DoWork(){x 5;var y x 10;Debug.WriteLine("x " x ", y " y);} }在 Releas…

跟我一起学.NetCore之MediatR好像有点火

前言随着微服务的流行&#xff0c;而DDD(领域驱动设计)也光速般兴起&#xff0c;CRQS(Command Query Responsibility Seperation--命令查询职责分离)、领域事件名词是不是经常在耳边环绕&#xff0c;而MediatR组件经常用来对其技术的落地&#xff0c;凭这&#xff0c;小伙伴们说…

数据结构 - 单调栈、单调队列

单调栈&#xff1a;每日温度 请根据每日 气温 列表 temperatures &#xff0c;请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替单调栈基本只处理NGE问题&#xff08;Next GreaterElement&#xff09;。对序列中每个元…

不想写脚本清理 mongodb 中的垃圾数据,ttlIndex 能帮到你!

mongodb一直都在不断的更新&#xff0c;不断的发展&#xff0c;那些非常好玩也非常实用的功能都逐步加入到了mongodb中&#xff0c;这不就有了本篇对ttlindex的介绍&#xff0c;刚好我们的生产业务场景中就有一个案例。。。一&#xff1a;案例分析 生产的推荐系统要给用户发送短…

数据结构 - 最小堆最大堆

可以在O(nlogn)的时间复杂度内完成排序典型的用法是&#xff0c;寻找 第k个/前k个 最大/最小元素&#xff0c;k个有序序列合并 1.合并K个升序链表&#xff08;最小堆实现&#xff09; 或许可以改进成每次堆只存放K个元素&#xff1f; # Definition for singly-linked list. …

python程序启动其他python程序,如何使用Python启动应用程序的实例?

I am creating a Python script where it does a bunch of tasks and one of those tasks is to launch and open an instance of Excel. What is the ideal way of accomplishing that in my script?解决方案While the Popen answers are reasonable for the general case, I…

工作这几年所获、所感、所悟

【导读】截止到目前&#xff0c;给甲方所做项目已接近尾声&#xff0c;在此写下一点个人关于技术方面的感受。若后续时间上允许或充裕的话&#xff0c;打算私下花一点时间分享封装可通用的组件今年也是我首次带小伙伴&#xff0c;有刚毕业没什么技术经验&#xff0c;也有毕业不…

后端学习 - 基础 《Java编程的逻辑》读书笔记

文章目录一 基础概念1 有关Java2 JVM / JDK / JRE3 与C的联系和区别4 各类型数据占用空间大小5 和 equals() 的区别、hashCode() 方法6 包装类型7 final 关键字8 参数传递机制&#xff1a;值传递9 String 的内存情况10 访问修饰符11 引用拷贝、浅拷贝与深拷贝三 面向对象1 面向…

cheatengine找不到数值_彩票中奖500万,领了还不到一半?这些问题不解决,钱都拿不走...

长期以来&#xff0c;“一夜暴富”是很多人梦寐以求的梦想&#xff0c;而作为最能让人“一夜暴富”的方式要数我国的福利彩票了&#xff0c;这也是很多人最容易活动暴富的机会&#xff0c;不少彩民长久以来一直买彩票的梦想就是“一夜暴富”。而突然暴富是很多人的梦想&#xf…

一站式Web开发套件BeetleX.WebFamily

BeetleX.WebFamily是一款前后端分离的Web开发套件&#xff0c;但它并不依赖于nodejs/npm/webpack等相关工具&#xff1b;而使用自身实现的方式来完成前后端分离的Web应用开发&#xff1b;套件以组件的方式发布&#xff0c;只需要在项目引用相关组件即可实现前后端分离开发&…

.NET架构小技巧(2)——访问修饰符正确姿势

在C#中&#xff0c;访问修饰符是使用频率很高的一组关键字&#xff0c;一共四个单词六个组合&#xff1a;public,internal,protected internal,protected,private protected,private&#xff0c;如果你对这些关键字非常清楚&#xff0c;请跳过&#xff0c;节省时间&#xff1b;…

能源36号文解读_IDC报告预测:今年中国新能源汽车销量将达116万辆,未来五年复合增长率36%_详细解读_最新资讯_热点事件...

编者按&#xff1a;本文来自36氪「 未来汽车日报」&#xff0c;(微信公众号ID&#xff1a;auto-time)&#xff0c;作者&#xff1a;秦章勇。 来源&#xff1a;IDC作者 | 秦章勇编辑 | 周游12月3日&#xff0c;在2020世界智能汽车大会上&#xff0c;IDG亚洲(国际数据(亚洲)集团)…

后端学习 - 容器

文章目录一 简介二 底层数据结构总结1 List2 Set3 Queue4 Map三 Collection 的子接口 List1 ArrayList 与 Vector2 ArrayList 与 LinkedList3 ArrayList 的 JDK 7/8 差异4 ArrayList 的构造方法与扩容机制*四 Collection 的子接口 Set1 HashSet、LinkedHashSet 和 TreeSet2 Has…

简单聊聊AspNetCore的启动流程

首先&#xff0c;得和大家达成一个共识&#xff0c;即AspNetCore项目其实就是一个控制台项目。可以简单的理解&#xff0c;AspNetCore就是将一个Web服务器宿主在一个进程(即控制台)中&#xff0c;然后它在这个进程中进行http请求的监听处理。AspNetCore中默认使用kestrel作为we…