尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

gRPC 核心概念详解:从 .proto 接口定义到 HTTP/2 之上的帧协议与流控

gRPC 核心概念详解:从 .proto 接口定义到 HTTP/2 之上的帧协议与流控 gRPC 核心概念详解从 .proto 接口定义到 HTTP/2 之上的帧协议与流控【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc本文基于 gRPC 官方仓库中的核心概念文档 CONCEPTS.md 展开系统讲解 gRPC 的接口抽象IDL 与代码生成、同步/异步调用模型、流式Streaming语义以及 gRPC 抽象协议如何在 HTTP/2 上落地为带 5 字节帧头的长度前缀帧。读完后你不仅能理解一次 gRPC 调用在客户端、服务端之间究竟发生了什么还能结合仓库中的示例 proto 与服务端/客户端实现看懂协议中每个组成部分Call Header、Initial-Metadata、Payload Messages、Status、Trailing-Metadata对应的实际行为。一、接口以语言无关的服务描述为起点gRPC 的本质是对远程过程调用RPC的具体实现客户端像调用本地函数一样调用远端服务而这一抽象的起点是一份语言无关的 RPC 服务描述一组方法的集合。gRPC 的 Protocol Compiler 插件会基于这份描述生成各受支持语言中的客户端与服务端接口——客户端通过这些生成的 API 发起远程调用服务端则实现对应的接口来响应调用。默认情况下gRPC 使用Protocol Buffers作为接口定义语言IDL同时描述服务接口和载荷消息的结构如有需要也可以使用其他替代方案例如 JSON详见下文协议部分content-type中application/grpcjson的约定。仓库中的示例 proto 是理解这一机制的最佳素材。以 helloworld.proto 为例一份典型的服务定义长这样syntax proto3; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {} rpc SayHelloBidiStream (stream HelloRequest) returns (stream HelloReply) {} } // The request message containing the users name. message HelloRequest { string name 1; } // The response message containing the greetings message HelloReply { string message 1; }这份.proto文件同时定义了服务Greeter及其三个方法一元、服务端流、双向流正好覆盖下文的调用模型与流式语义请求消息HelloRequest与响应消息HelloReply的字段结构与字段编号。代码生成的实现位于 src/compiler 目录其中 cpp_plugin.cc、python_plugin.cc、node_plugin.cc、ruby_plugin.cc、csharp_plugin.cc、objective_c_plugin.cc 等各自对应一种受支持语言的 protoc 插件src/proto/grpc/下则存放了 gRPC 官方自带的 proto 定义。二、发起与处理远程调用同步与异步两种编程面RPC 希望尽可能贴近过程调用的抽象因此同步调用阻塞直至服务端返回响应是最接近这一抽象的形态但网络本质上是异步的许多场景下希望在当前线程不被阻塞的前提下发起调用。为此gRPC 在大多数语言中的编程面都提供同步与异步两种风格。这一点在 examples/cpp/helloworld 目录的文件组织上体现得非常直接文件调用风格greeter_client.cc / greeter_server.cc同步客户端 / 同步服务端greeter_async_client.cc、greeter_async_client2.cc / greeter_async_server.cc基于 Completion Queue 的异步客户端 / 服务端greeter_callback_client.cc / greeter_callback_server.cc回调风格的客户端 / 服务端也就是说同一个Greeter服务在 C 侧就有同步、CQ 异步、回调三套可直接运行的实现范式读者可以按自己的并发模型自由选择。三、流式Streaming单个 RPC 上的多消息语义gRPC 支持流式语义在单个 RPC 调用中客户端或服务端或双方都可以发送一条消息流。最一般的情形是双向流Bidirectional Streaming——一次 gRPC 调用建立起一条流双方各自向其发送消息流。流式消息按发送顺序投递ordered delivery。结合上文 proto 示例gRPC 的四种调用形态一目了然形态请求响应示例方法一元单条消息单条消息SayHello服务端流单条消息消息流SayHelloStreamReply客户端流消息流单条消息可在任意 service 中以rpc M (stream Req) returns (R)声明双向流消息流消息流SayHelloBidiStream仓库中还有专门的流式示例 hellostreamingworld.proto其中MultiGreeter.sayHello方法根据请求中的num_greetings字段回复多条问候对应 examples/python/hellostreamingworld 与 examples/node 等目录下的可运行客户端/服务端可作为服务端流的最小实操参考。从协议视角看流式并非特殊机制无论一元还是流式一次调用都是一条双向消息流见下节一元调用只是流中恰好只有一条 Payload Message的特例因此流式与一元在传输层完全同构。四、gRPC 抽象协议一次调用的消息原子CONCEPTS.md 中定义的抽象协议描述了一次 gRPC 调用由哪些部分构成客户端 → 服务端方向以强制的Call Header开始随后是可选的Initial-Metadata再是零条或多条Payload Messages。客户端通过底层协议机制在 HTTP/2 上即 END_STREAM 标志来宣告自己消息流的结束。服务端 → 客户端方向包含可选的Initial-Metadata随后是零条或多条Payload Messages最后以强制的Status和可选的Status-Metadata又称Trailing-Metadata收尾。注意两个关键约束Call Header和Status是强制的——前者承载方法名、路径等调用定义信息后者承载 gRPC 状态码即使成功也必须发送客户端消息流的结束由底层传输表达而不是在 gRPC 层写一个特殊的结束消息。五、HTTP/2 上的具体实现帧结构、编码与状态传递上述抽象协议的具体落地是基于 HTTP/2 的完整细节见 doc/PROTOCOL-HTTP2.md。核心映射关系如下5.1 抽象概念与 HTTP/2 机制的对应gRPC 抽象概念HTTP/2 上的承载gRPC 双向流HTTP/2 stream一条 gRPC 调用 一条 HTTP/2 流Call HeaderInitial-MetadataHTTP/2 请求头HEADERS CONTINUATION 帧受HPACK 压缩Payload MessagesDATA 帧内部为长度前缀的 gRPC 帧发送方切分为 HTTP/2 DATA 帧、接收方重组StatusTrailing-MetadataHTTP/2 尾随头trailers客户端消息流结束最后一个 DATA 帧上设置END_STREAM标志5.2 请求头中的调用定义按 doc/PROTOCOL-HTTP2.md 的 ABNF 规则请求头即调用定义Request-Headers → Call-Definition *Custom-Metadata Call-Definition → Method Scheme Path [Authority] TE [Timeout] Content-Type [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent]其中几个要点值得展开Path形如/Service-Name/Method大小写敏感。文档明确指出若 Path 不采用该形式一些功能例如 service config 支持将无法工作Timeout通过grpc-timeout头传递取值为最多 8 位的十进制整数加单位字符H/M/S/m/u/n对应时/分/秒/毫秒/微秒/纳秒若省略 Timeout服务端应视为无限超时Content-Type必须以application/grpc开头可带proto、json等后缀若不满足服务端应当以 HTTP 415Unsupported Media Type应答以此防止其他 HTTP/2 客户端把 gRPC 错误响应HTTP 状态码恒为 200误判为成功压缩协商通过grpc-encoding消息编码与grpc-accept-encoding完成编码可以是identity、gzip、deflate、snappy或自定义。5.3 消息帧1 字节标志 4 字节长度 消息体DATA 帧中承载的是Length-Prefixed-Message序列其线格式为Length-Prefixed-Message → Compressed-Flag Message-Length Message Compressed-Flag → 0 / 1 ; 1 字节无符号整数 Message-Length → {Message 长度} ; 4 字节无符号整数大端 Message → *{binary octet}即每条 gRPC 消息在流上都是5 字节头 消息体的形式。规则上有两条容易踩坑的细节Compressed-Flag为 1 表示消息体按grpc-encoding头声明的机制压缩过为 0 表示未编码。压缩上下文不跨消息边界保持——每条消息都必须新建压缩上下文若未发送grpc-encoding头该标志必须为 0请求的 EOSend-of-stream由最后一个 DATA 帧上的END_STREAM标志表达若流需要关闭但没有剩余数据要发实现方必须发送一个带该标志的空 DATA 帧。5.4 响应与状态Trailers 与 Trailers-Only响应形式为Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only Trailers → Status [Status-Message] [Status-Details] *Custom-Metadata Status → grpc-status 1*digit要点grpc-status是 0-9 的十进制数字即 gRPC 状态码0 表示 OK通过grpc-message头携带百分号编码的状态文本grpc-status-details-bin可携带 base64 编码的附加错误详情即使状态码是 OKStatus 也必须在 Trailers 中发送——这正是一元调用结果放在哪的协议层答案响应体里不放状态状态永远走 trailersTrailers-Only无响应头与消息体、直接发 trailers仅用于立即出错的调用场景例如认证失败、快速失败的参数错误等响应的流结束由携带 Trailers 的最后一个 HEADERS 帧上的END_STREAM标志表达。5.5 自定义 Metadata 的编码约束自定义 metadataCustom-Metadata分两类ASCII 头与二进制头。二进制头的键名以-bin结尾值必须按 RFC 4648 做Base64 编码HTTP/2 不允许头值中携带任意字节序列实现方必须同时接受带填充与不带填充的 Base64 值且应当输出不带填充的值。另外以grpc-开头但未被协议占用的键名保留给 gRPC 未来使用应用不应将其用作自定义 metadata。六、流控直接复用 HTTP/2 的机制CONCEPTS.md 对流控的表述非常简短但信息量足够gRPC 使用 HTTP/2 的流控机制从而能够对在途消息的缓冲内存做细粒度控制。这意味着流控单元就是 HTTP/2 的 DATA 字节流接收方通过 WINDOW_UPDATE 帧按流和按连接两个维度授予发送配额发送方不得超额发送由于 gRPC 帧5 字节头 消息体在 HTTP/2 层被切分成多个 DATA 帧窗口耗尽会天然反压到 gRPC 的消息发送无需 gRPC 层再维护一套独立的缓冲配额对双向流而言两个方向各自有独立的窗口客户端的发送速度不会被服务端慢消费拖垮全局——这是细粒度内存控制的实际含义缓冲内存的规模由窗口大小决定而不是由消息数量决定。这一设计与第五章的帧结构天然契合接收方在重组Length-Prefixed-Message之前HTTP/2 层已经保证了未重组数据的总量不超过窗口额度。七、在仓库中继续深入协议完整规范含全部 ABNF 生产规则、错误码映射doc/PROTOCOL-HTTP2.md传输层实现入口gRPC 的各传输实现位于 src/core/ext/transport如 chaotic_good/frame.cc、frame_header.cc 中的帧读写逻辑可对照第五章的帧格式查看字节级处理接口定义与生成examples/protos/helloworld.proto、examples/protos/hellostreamingworld.proto、src/compiler可运行的同步/异步/回调三种调用风格示例examples/cpp/helloworld流控与连接行为的配套文档doc/keepalive.md、doc/connectivity-semantics-and-api.md状态码语义doc/statuscodes.md对应协议中的grpc-status【免费下载链接】grpcC based gRPC (C, Python, Ruby, Objective-C, PHP, C#)项目地址: https://gitcode.com/GitHub_Trending/gr/grpc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表