后台技术gRPC基础概念详解

本文介绍gRPC的基础概念。首先通过关系图直观展示这些基础概念之间关联,介绍异步gRPC的Server和Client的逻辑;然后介绍RPC的类型,阅读和抓包分析gRPC的通信过程协议,gRPC上下文;最后分析grpc.pb.h文件的内容,包括Stub的能力、Service的种类以及与核心库的关系。

之所以谓之基础,是这些内容基本不涉及gRPCCore的内容。

上图中列出了gRPC基础概念及其关系图。其中包括:Service(定义)、RPC、API、Client、Stub、Channel、Server、Service(实现)、ServiceBuilder等。

接下来,以官方提供的example/helloworld为例进行说明。

.proto文件定义了服务Greeter和APISayHello:

classGreeterClient是Client,是对Stub封装;通过Stub可以真正的调用RPC请求。

Channel提供一个与特定gRPCserver的主机和端口建立的连接。

Stub就是在Channel的基础上创建而成的。

Server端需要实现对应的RPC,所有的RPC组成了Service:

Server的创建需要一个Builder,添加上监听的地址和端口,注册上该端口上绑定的服务,最后构建出Server并启动:

RPC和API的区别:RPC(RemoteProcedureCall)是一次远程过程调用的整个动作,而API(ApplicationProgrammingInterface)是不同语言在实现RPC中的具体接口。一个RPC可能对应多种API,比如同步的、异步的、回调的。一次RPC是对某个API的一次调用,比如:

不管是哪种类型RPC,都是由Client发起请求。

Client看文档可以理解,但Server的代码复杂,文档和注释中的解释并不是很好理解,接下来会多做一些解释。

1.异步Client

greeter_async_client.cc中是异步Client的Demo,其中只有一次请求,逻辑简单。

stub_->PrepareAsyncSayHello()+rpc->StartCall()

stub_->AsyncSayHello()

2.异步Server

RequestSayHello()这个函数没有任何的说明。只说是:"we*request*thatthesystemstartprocessingSayHellorequests."也没有说跟cq_->Next(&tag,&ok);的关系。我这里通过加上一些日志打印,来更清晰的展示Server的逻辑:

上边绿色的部分为创建的第一个CallData对象地址,橙色的为第二个CallData的地址。

传入ServerContextctx_

传入HelloRequestrequest_

传入ServerAsyncResponseWriterresponder_

传入ServerCompletionQueue*cq_

将对象自身的地址作为tag传入

该动作,能将事件加入事件循环,可以在CompletionQueue中等待

创建新的CallData对象以接收新请求

处理消息体并设置reply_

将状态设置为FINISH

调用responder_.Finish()将返回发送给客户端

该动作,能将事件加入到事件循环,可以在CompletionQueue中等待

3.关系图

将上边的异步Client和异步Server的逻辑通过关系图进行展示。右侧RPC为创建的对象中的内存容,左侧使用相同颜色的小块进行代替。

以下CallData并非gRPC中的概念,而是异步Server在实现过程中为了方便进行的封装,其中的Status也是在异步调用过程中自定义的、用于转移的状态。

4.异步Client2

在example/cpp/helloworld中还有另外一个异步Client,对应文件名为greeter_async_client2.cc。这个例子中使用了两个线程去分别进行发送请求和处理返回,一个线程批量发出100个SayHello的请求,另外一个不断的通过cq_.Next()来等待返回。

无论是Client还是Server,在以异步方式进行处理时,都要预先分配好一定的内存/对象,以存储异步的请求或返回。

5.回调方式的异步调用

使用回调方式简介明了,结构上与同步方式相差不多,但是并发有本质的区别。可以通过文件对比,来查看其中的差异。

其实,回调方式的异步调用属于实验性质的,不建议直接在生产环境使用,这里也只做简单的介绍:

5.1回调Client

发送单个请求,在调用SayHello时,除了传入Request、Reply的地址之外,还需要传入一个接收Status的回调函数。

例子中只有一个请求,因此在SayHello之后,就直接通过condition_variable的wait函数等待回调结束,然后进行后续处理。这样其实不能进行并发,跟同步请求差别不大。如果要进行大规模的并发,还是需要使用额外的对象进行封装一下。

5.2回调Server

与同步Server不同的是:

可以按照Client和Server一次发送/返回的是单个消息还是多个消息,将gRPC分为:

1.Server对RPC的实现

Server需要实现proto中定义的RPC,每种RPC的实现都需要将ServerContext作为参数输入。

如果是一元(Unary)RPC调用,则像调用普通函数一样。将Request和Reply的对象地址作为参数传入,函数中将根据Request的内容,在Reply的地址上写上对应的返回内容。

如果涉及到流,则会用Reader或/和Writer作为参数,读取流内容。如ServerStream模式下,只有Server端产生流,这时对应的Server返回内容,需要使用作为参数传入的ServerWriter。这类似于以'w'打开一个文件,持续的往里写内容,直到没有内容可写关闭。

另一方面,Client来的流,Server需要使用一个ServerReader来接收。这类似于打开一个文件,读其中的内容,直到读到EOF为止类似。

如果Client和Server都使用流,也就是Bidirectional-Stream模式下,输入参数除了ServerContext之外,只有一个ServerReaderWriter指针。通过该指针,既能读Client来的流,又能写Server产生的流。

例子中,Server不断地从stream中读,读到了就将对应的写过写到stream中,直到客户端告知结束;Server处理完所有数据之后,直接返回状态码即可。

2.Client对RPC的调用

Client在调用一元(Unary)RPC时,像调用普通函数一样,除了传入ClientContext之外,将Request和Response的地址,返回的是RPC状态:

Client在调用ServerStreamRPC时,不会得到状态,而是返回一个ClientReader的指针:

Reader通过不断的Read(),来不断的读取流,结束时Read()会返回false;通过调用Finish()来读取返回状态。

调用ClientStreamRPC时,则会返回一个ClientWriter指针:

Writer会不断的调用Write()函数将流中的消息发出;发送完成后调用WriteDone()来说明发送完毕;调用Finish()来等待对端发送状态。

而双向流的RPC时,会返回ClientReaderWriter,:

前面说明了Reader和Writer读取和发送完成的函数调用。因为RPC都是Client请求而后Server响应,双向流也是要Client先发送完自己流,才有Server才可能结束RPC。所以对于双向流的结束过程是:

示例中创建了单独的一个线程去发送请求流,在主线程中读返回流,实现了一定程度上的并发。

3.流是会结束的

并不似长连接,建立上之后就一直保持,有消息的时候发送。(是否有通过建立一个流RPC建立推送机制?)

Server并没有像Client一样调用WriteDone(),而是在消息之后,将statuscode、可选的statusmessage、可选的trailingmetadata追加进行发送,这就意味着流结束了。

本节通过介绍gRPC协议文档描述和对helloworld的抓包,来说明gRPC到底是如何传输的。

1.ABNF语法

2.请求协议

*表示element会重复多次(最少0次)。知道这个就能理解概况里的描述了:

这表示Request是由3部分组成,首先是Request-Headers,接下来是可能多次出现的Length-Prefixed-Message,最后以一个EOS结尾(EOS表示End-Of-Stream)。

2.1Request-Headers

根据上边的协议描述,Request-Headers是由一个Call-Definition和若干Custom-Metadata组成。

[]表示最多出现一次,比如Call-Definition有很多组成部分,其中Message-Type等是选填的:

通过Wireshark抓包可以看到请求的Call-Definition中共有所有要求的Header,还有额外可选的,比如user-agent:

因为helloworld的示例比较简单,请求中没有填写自定义的元数据(Custom-Metadata)

2.2Length-Prefixed-Message

传输的Length-Prefixed-Message也分为三部分:

同样的,Wireshark抓到的请求中也有这部分信息,并且设置.proto文件的搜索路径之后可以自动解析PB:

其中第一个红框(Compressed-Flag)表示不进行压缩,第二个红框(Message-Length)表示消息长度为7,蓝色反选部分则是Protobuf序列化的二进制内容,也就是Message。

这里Length-Prefixed-Message中传输的可以是PB也可以是JSON,须通过Content-Type头中描述告知。

2.3EOS

End-Of-Stream并没有单独的数据去描述,而是通过HTTP2的数据帧上带一个END_STREAM的flag来标识的。比如helloworld中请求的数据帧,也携带了END_STREAM的标签:

3.返回协议

()表示括号中的内容作为单个元素对待,/表示前后两个元素可选其一。Response的定义说明,可以有两种返回形式,一种是消息头、消息体、Trailer,另外一种是只带Trailer:

这里需要区分gRPC的Status和HTTP的Status两种状态。

不管是哪种形式,最后一部分都是Trailers,其中包含了gRPC的状态码、状态信息和额外的自定义元数据。

同样地,使用END_STREAM的flag标识最后Trailer的结束。

4.与HTTP/2的关系

ThelibrariesinthisrepositoryprovideaconcreteimplemnetationofthegRPCprotocol,layeredoverHTTP/2.

gRPC支持上下文的传递,其主要用途有:

客户端添加自定义的metadatakey-value对没有特别的区分,而服务端添加的,则有inital和trailing两种metadata的区分。这也分别对应这ClientContext只有一个添加Metadata的函数:

而ServerContext则有两个:

还有一种CallbackServer对应的上下文叫做CallbackServerContext,它与ServerContext继承自同一个基类,功能基本上相同。区别在于:

1.Stub

.proto中的一个service只有一个Stub,该类中会提供对应每个RPC所有的同步、异步、回调等方式的函数都包含在该类中,而该类继承自接口类StubInterface。

为什么需要一个StubInterface来让Stub继承,而不是直接产生Stub?别的复杂的proto会有多个Stub继承同一个StubInterface的情况?不会,因为每个RPC对应的函数名是不同。

Greeter中唯一一个函数是用于创建Stub的静态函数NewStub:

Stub中同步、异步方式的函数是直接作为Stub的成员函数提供,比如针对一元调用:

回调方式的RPC调用是通过一个experimental_async的类进行了封装(有个async_stub_的成员变量),所以回调Client中提到,回调的调用方式用法是stub_->async()->SayHello(...)。

experimental_async类定义中将Stub类作为自己的友元,自己的成员可以被Stub直接访问,而在StubInterface中也对应有一个experimental_async_interface的接口类,规定了要实现哪些接口。

2.Service

有几个概念都叫Service:proto文件中RPC的集合、proto文件中service产生源文件中的Greeter::Service类、gRPC框架中的::grpc::Service类。本小节说的Service就是helloworld.grpc.pb.h中的Greeter::Service。

2.1Service是如何定义的

helloworld.grpc.pb.h文件中共定义了7种Service,拿出最常用的Service和AsyncService两个定义来说明下Service的定义过程:通过类模板链式继承。

Service跟其他几种Service不同,直接继承自grpc::Service,而其他的Service都是由类模板构造出来的,而且使用类模板进行嵌套,最基础的类就是这里的Service。

Service有以下特点:

所以Service类中的所有RPCAPI都是同步的。

再看AsyncService的具体定义:

所以AsyncService的含义就是继承自Service,加上了WithAsyncMethod_SayHello的新功能:

通过gRPC提供的route_guide.proto例子能更明显的理解这点:

这里RouteGuide服务中有4个RPC,GetFeature、ListFeatures、RecordRoute、RouteChat,通过4个WithAsyncMethod_{RPC_name}的类模板嵌套,能将4个API都设置成ApiType::ASYNC、添加上对应的RequestXXX()函数、禁用同步函数。

2.2Service的种类

helloworld.grpc.pb.h文件中7种Service中,有3对Service的真正含义都相同(出于什么目的使用不同的名称?),实际只剩下4种Service。前三种在前边的同步、异步、回调Server的介绍中都有涉及。

其实这些不同类型的Service是跟前边提到的api_type_有关。使用不同的::grpc::Service::MarkMethodXXX设置不同的ApiType会产生不同的API模板类,所有API模板类级联起来,就得到了不同的Service。这三者的关系简单列举如下:

另外还有两种模板是通过设置其他属性产生的,这里暂时不做介绍:

3.与::grpc核心库的关系

Stub类中主要是用到gRPCChannel和不同类型RPC对应的方法实现

Service类则继承自::grpc::Service具备其父类的能力,需要自己实现一些RPC方法具体的处理逻辑。其它Service涉及到gRPC核心库的联系有:

AsyncService::RequestSayHello()调用::grpc::Service::RequestAsyncUnary。

CallbackService::SayHello()函数返回的是::grpc::ServerUnaryReactor指针。

CallbackService::SetMessageAllocatorFor_SayHello()函数中调用

::grpc::internal::CallbackUnaryHandler::SetMessageAllocator()函数设置RPC方法的回调的消息分配器。

THE END
1.在线代码编辑器codeserver真正做了一次安装,到处使用。 什么是 code-server ? code-server是一个免费的基于浏览器的IDE,可以让我们在具有一致开发环境的任何设备上编写代码。 还有个项目叫OpenVSCode,和code-server似乎是一样的,等有空了再来研究 准备 如果你要在互联网上使用,需要先准备好一个域名,并做好反向代理设置,因为后面安装容器的https://blog.csdn.net/wbsu2004/article/details/124538062
2.codeVisual Studio Code(简称 vscode)是一款由微软开发且跨平台的免费源代码编辑器,结合插件能够用于多种语言程序开发(如 python, java, javascript, go 等)。但是其属于一款客户端软件,在远程服务器上使用不如 code-server,code-server 是一款能够在网页上使用的 vscode,极大的方便程序开发人员快速访问与编码。本篇介绍https://xujinzh.github.io/2024/04/10/install-code-server/
3.随时随地写代码基于Codecode-server和vscode一样,支持安装插件,我选择了几个常用的插件安装测试,均完美支持。 界面 Tips 因为code-server专注于编辑器而对语言本身稍有忽略,比如其内置的python没有pip3工具,需要自己安装;而且内置的deb源速度较慢,需要自行替换。 修改deb源 因为自带的vi不要用,所以我们使用以下方式修改deb源,参考:常用工具https://cloud.tencent.com/developer/article/2064025
4.数据点不过,随着 VS Code 插件不断增多(当我在 2017 年 4 月下旬撰写本文时,仅略低于 3,000),许多用于与数据存储进行交互的插件现已发布。我用过两个,分别是来自 SQL Server 团队的 mssql 插件 (bit.ly/2gb2ICf),以及适用于 SQLite 和 PostgreSQL 的 vscode-database 插件 (https://docs.microsoft.com/zh-cn/archive/msdn-magazine/2017/june/data-points-visual-studio-code-create-a-database-ide-with-mssql-extension
5.VSCodeWebIDECoder安装及使用其它综合Coder是VS Code的Web IDE,分Code Server 和 Coder,Code Server安装在服务器上,通过浏览器打开地址后可以使用一个web版的VS Code,也就是Coder,但VS Code的插件无法使用。这篇文章主要介绍了VSCode Web IDE Coder 安装及使用,需要的朋友可以参考下GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!【 如果你想靠https://www.jb51.net/article/231012.htm
6.轻松搭建一个在线版的VSCode编辑器四、解压并使用 下载好后我们需要对其进行解压,如图: image.png 解压完毕后就有一个文件夹,我们要想使用就要启动里面的code-server文件,如图: image.png 此时我们只需要访问http://127.0.0.1:8080/即可打开web版VSCode,如图: image.png 不过这里i需要我们输入密码,那么这又该怎么做了,其实我们可以自定义一组密码https://www.jianshu.com/p/7d4b83be496c
7.通过ESXI安装HomeAssistantOS,必装插件推荐Studio Code Server 安装Studio Code Server后,可以直接在浏览器中修改configuration.yaml文件,或其他HA系统文件。 Home Assistant Google Drive Backup 提供自动备份HA系统,并同步到Google云盘,强烈推荐大家开启自动备份,HA系统更新频繁,如果遇到新系统不兼容,可以回滚备份回到之前的版本。 https://sspai.com/post/73363
8.干货利用vscode远程调试Linux内核我这里使用的是私钥方式登陆服务器,IdentityFile填写的是私钥的绝对路径。 配置好后,点击加号按钮,就可以登陆服务器了 报错:Setting up SSH Host XX:Copying VS Code Server to host with scp 在进行连接的时候卡住了,一直在等待Setting up SSH Host XX:Copying VS Code Server to host with scp。 https://www.eefocus.com/article/517941.html
9.Java加密技术HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别https://www.iteye.com/blog/lzchacker-1820594
10.compose)。这些工具也可以独立使用,比如项目构建部署发布这些工具也可以独立使用,比如项目构建、部署发布、Webhook server、dns修改、服务器登录异常警报、数据库备份归档与还原、表格绘制、申请与续签(泛)域名证书等等,具体参考帮助。写文档是挺费神的,将就看吧。如果你在使用中遇到任何问题请在Issues中提出,或留下联系方式线下沟通。 1.1 特点 项目构建:可以指定构建方法、https://gitee.com/dataframe/zzxia-op-super-invincible-lollipop
11.code登录腾讯云开发者社区一直以来,VS Code 都是开发者心目中的生产力神器,它免费、开源且跨平台,被称为最好用的 IDE。把 VS Code 和 ChatGPT 结合使用,用户将获得来自 AI 的编程指导,包括代码解释、找 bug 等功能。但作者表示,目前 VSCode ChatGPT 的免登录、免注册、免代理版本已经上线,并在 VSCode 的插件商店提供了更新https://cloud.tencent.cn/developer/information/code%E7%99%BB%E5%BD%95-article
12.我要自学网我要自学网-免费视频教程,提供全方位软件学习,有3D教程,平面教程,多媒体制作教程,办公信息化教程,机械设计教程,网站制作教程,电脑培训http://51zxw.net/
13.app本地webhttpserver插件插件ID:wrs-httpserver 插件包体积:590.2KB 更新日期:2024-02-23 版本:1.0.12 插件 购买(199.00 元)for 云打包试用 示例 使用HBuilderX 导入示例项目 本站所有收费插件均支持免费试用,切勿私下交易或购买不可正常试用的插件,而造成不必要的纠纷。 更新记录 https://ext.dcloud.net.cn/plugin?id=5491
14.解决VSCode自动更新版本后卡在连接界面晚花行乐如果不想每次自动更新后都手动执行一次脚本,那么可以关闭 VS Code 的自动更新。 打开Setting, 搜索update关键字,按照图中红框里的选项配置即可。 如果您对本文有疑问或者寻求合作,欢迎联系邮箱。邮箱已到剪贴板 给个免费的赞吧~ 0 ? 前一篇: 在 Windows 10 LTSC 版本上安装 WSL2 https://www.lfhacks.com/tech/vscode-server/
15.花椒直播伴侣和QuickWAP2005哪个好用花椒直播伴侣和QuickWAP它解决了WAP开发中所遇到的常见问题,并且给出了完善的解决方案,同时全力支持Microsoft SQL Server2000和Microsoft Access2000以上版本数据库,是开发功能强大的动态WAP网站不可多得的辅助软件。 使用QuickWAP组件编写WAP网页程序,不仅运行稳定,处理速度也会比相同功能的ASP+WML网页程序要快很多倍,功能容易得到扩展,而且https://xiazai.zol.com.cn/pk/433528_262982.shtml
16.京东(JD.COM)京东JD.COM-专业的综合网上购物商城,为您提供正品低价的购物选择、优质便捷的服务体验。商品来自全球数十万品牌商家,囊括家电、手机、电脑、服装、居家、母婴、美妆、个护、食品、生鲜等丰富品类,满足各种购物需求。http://jd.com/
17.华为华为创立于1987年,是全球领先的ICT(信息与通信)基础设施和智能终端提供商,致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界。http://www.huawei.cn/
18.调用BindEcsSlb接口来给部署在ECS集群中的应用绑定SLB{ "ChangeOrderId": "cd65b247-***-475b-ad4b-7039040d625c", "Code": 200, "Message": "success", "RequestId": "03FD1520-0FD6-436A-***-265318D7***" } JSON格式 { "ChangeOrderId": "cd65b247-***-475b-ad4b-7039040d625c", "Code": 200, "Message": "success", "RequestIdhttps://help.aliyun.com/zh/edas/developer-reference/api-edas-2017-08-01-bindecsslb
19.亲测能用SideFXHoudiniFXv20附安装教程免费破解版安装本页面免费提供:SideFX Houdini FX v20【附安装教程】免费破解版安装图文教程,通过详细的软件安装步骤,帮助您快速成功安装软件及使用,亲测能用!https://www.yutu.cn/softhtml/softsetup_8885.html