后台技术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.AzureDevOpsServer:集成奇安信代码卫士(CodeSafe)本文主要介绍集成Azure DevOps Server和奇安信代码卫士的方法,并在持续集成的实践中应用这个产品。 2. 实现方法 2.1 安装插件 为了实现Azure DevOps Server和奇安信开源卫士的集成,奇安信公司开发了一款Azure DevOps Server扩展插件,名称为“QAX Code Safe” https://blog.csdn.net/dev66/article/details/145435484
2.快速开发新境界,低代码平台解锁项目高效编程服务器工作流应用低代码(Low-code)是指一种应用程序开发方法,它通过图形化的用户界面让开发者可以通过拖拽组件、配置参数等操作来创建应用,而不是编写大量底层代码。这种方式大大降低了编程难度,提高了开发效率,使得即使是不具备深厚编程背景的人也能参与到应用开发中来。低代码平台通常包含预构建的功能模块、模板和API接口,支持多端部https://www.163.com/dy/article/JM2AVQ3K0518CPJB.html
3.低代码开发平台唛盟lcode:低代码开发平台 简介唛盟低代码开发平台mdp-lcode 唛盟低代码开发平台简称唛盟或者mdp. 唛盟-总体介绍 唛盟旨在为企业开发业务系统提供一整套解决方案,唛盟具有高效率、低代码、支持0代码、功能丰富等特点。企业可以在唛盟工程之上,加入更多其它业务功能;也可以以唛盟作为模板,创建新的工程,用于开发其它业务。使用唛盟构建https://gitee.com/maimengcloud/mdp-lcode-ui-web
4.OneCode一路走来OneCode 开源范围及功能: OneCode 第一个版本,以V5版本的引擎为核心,将平台全部600余组件的2/3贡献到社区版本,同时为方便大家构建自身的工程体系,还会同步开源 OneCode V3版本的支持环境VFS(JAVA开发)虚拟存储系统,以及配合V3 部署使用的 OneCode Server 和相关的部署管理插件。 https://developer.aliyun.com/article/1198565
5.IBMServer市场价格走势报告与分析:究竟多少钱?(ibmservice分区有IBMServer作为市场上的知名品牌,其价格走势及功能特点一直是广大用户关注的焦点。 本报告旨在分析IBMServer的市场价格走势,探讨其价格背后的原因,并简要介绍IBMService分区的功能。 二、IBMServer市场价格走势分析 1. 价格概况 IBMServer的价格根据型号、配置、市场供需等因素而有所差异。 https://www.ulidc.com/2025/02/01/ibmserver%E5%B8%82%E5%9C%BA%E4%BB%B7%E6%A0%BC%E8%B5%B0%E5%8A%BF%E6%8A%A5%E5%91%8A%E4%B8%8E%E5%88%86%E6%9E%90%EF%BC%9A%E7%A9%B6%E7%AB%9F%E5%A4%9A%E5%B0%91%E9%92%B1%EF%BC%9F-ibmservice%E5%88%86/
6.深入理解Electron(二)VSCode架构探索背景说起建立在Electron之上以上是VS Code源码的核心组织架构。通过code和server作为入口,workbench作为主框架,而editor、platform和base则成为这个庞大应用的基石。 由于VSCode本身同时提供面向浏览器的版本和客户端的版本,所以在二级目录下整体的目录结构又是跟所支持的目标平台环境有关: https://article.juejin.cn/post/7205044806275743801
7.定制返回JSON的数据和结构RealTimecoding特点功能 对于后端 提供万能通用接口,大部分 HTTP API 不用再写 零代码增删改查、各种跨库连表、JOIN 嵌套子查询等 自动生成文档,不用再编写和维护,且自动静态检查 自动校验权限、自动管理版本、自动防 SQL 注入 开放HTTP API 无需划分版本,始终保持兼容 https://github.com/Tencent/APIJSON
8.IBMAIX常见问题处理:《转载》mdl96304, 查看node_down和node_down_complete事件时,需要查看 /usr/es/adm/cluster.log和/tmp/hacmp.out 5, 在一个活动的HACMP v5.1集群中,下列服务是必须的 topsvcs grpsvcs emaixos emsvcs clstmgrES 6, HACMPv5.x 中的enhanced concurrent VG 能够被定义成一个共享的文件系统(无所谓是否是裸设备或者jfs,jfs2)http://blog.chinaunix.net/uid-23280800-id-4278673.html
9.在浏览器上运行VSCode——GitHub热点速览v.21.22这个项目竟然一直没被我发现过!Code-server 是一个让你能在浏览器中运行 VS Code 的工具。特性: 可在具有一致开发环境的任何设备上写代码 用云服务来加速测试、编译、下载等等功能 除此之外,code-server 还支持丰富的 VS Code 插件。 GitHub 地址→https://github.com/cdr/code-server https://cloud.tencent.com/developer/article/1838804
10.centos搭建codeserver配置HTTPS登录页自定义实现步骤其它综合功能预览 一、Code-Server Code-Server是一款网页版的IDE,相当于VSCode网页版(vscode.dev/),搭建完成后可以随时随地访问自己的代码 主要用途是让用户可以在任意设备和平台上使用基于web的IDE来进行编程工作。通过Code-Server可以使用浏览器访问远程服务器上的IDE,而无需在本地安装软件和配置开发环境。这对于不方便或不https://www.jb51.net/article/283544.htm
11.windowsVScode配置dockers环境vscodeserverdockercode-server 是一个基于 Visual Studio Code 的开源项目,它允许你通过 Web 浏览器来使用 Visual Studio Code 的编辑功能。这意味着你可以在任何设备上,只要有浏览器和网络连接,就可以访问和使用 Visual Studio Code,而无需在本地安装开发环境。 以下是 code-server 的一些特点和功能介绍: https://blog.51cto.com/u_16099165/11751541
12.code中文翻译:关闭遥测相关功能,使其不再收集和发送相关数据信息。 --disable-update-check: 说明:禁用更新检查。若不添加此标志,code-server会每隔 6 小时对照最新的GitHub版本进行检查,并每周通知一次有新版本可用。 中文翻译:禁止进行版本更新检查操作。若未使用该标识,code-server软件将会每间隔 6 个小时去比对查看是https://www.emchaye.cn/docs/tutorial-debian/20241217-02/
13..NETFramework中的新增功能.NET Framework 4.7.2 的持续关注是改进辅助功能的可访问性,这样应用程序就可以为辅助技术的用户提供适当的体验。 有关 .NET Framework 4.7.2 中的辅助功能改进的信息,请参阅 .NET Framework 中辅助功能的新特点。基类.NET Framework 4.7.2 具有大量加密增强功能、对 ZIP 存档的更好的解压缩支持和其他收集 APIhttps://docs.microsoft.com/zh-cn/dotnet/framework/whats-new/
14.AAA和用户管理原理描述ME60V800R023C10SPC500特性描述对RADIUS服务器状态探测功能:收到AAA的认证或计费消息后,如果当前服务器的状态为Down,启动服务器探测处理,将消息转换为报文后向当前服务器发送,该报文作为服务器的探测报文,如果收到RADIUS服务器的回应,则认为该服务器重新可用。 RADIUS服务器的自动切换功能:如果当前发送的服务器的状态为不可发送,或者发送次数超过当前https://support.huawei.com/enterprise/zh/doc/EDOC1100366534/efa34814
15.code但是其属于一款客户端软件,在远程服务器上使用不如 code-server,code-server 是一款能够在网页上使用的 vscode,极大的方便程序开发人员快速访问与编码。本篇介绍如何在 ubuntu 18.04 上安装和配置,使其适用于 python 开发。 安装 bash 1 2 3 4 5 6https://xujinzh.github.io/2024/04/10/install-code-server/
16.光学成像设计软件我们的客户支持团队由CODE V专家、经验丰富的光学工程师组成。如果您需要帮助,可随时联系我们,我们将与您分享视频、文档、教程、示例模型等。 主要特点 设计优化(包括全局优化功能)加速产品投入市场 快速,精准的公差分析对产品制造提供卓越支持 具有突破性创新的精准光束传播分析 https://www.synopsys.com/zh-cn/optical-solutions/codev.html
17.vscode下载vscode中文版手机版下载v1.0.0vscode是一款可以在手机客户端进行的免费代码编辑软件,采用Linux Arm64 启动一个 code-server,和本地内容资源的加载,结合现有的元素和功能系统进行打造,让众多的玩家们可以在手机上的实现自动编辑和代码转换的操作,感兴趣的小伙伴可以一起来免费下载试试哦。 软件功能 功能特点远程仓库 : 加载 git 代码 ,就像本地打https://app.ali213.net/android/485549.html