Chapter 4. gRP: Under the hood

本文详细介绍了gRPC的工作流程,从客户端使用stub调用RPC函数,到HTTP/2的请求和响应消息传递,包括message的编码技术如Protocol Buffers,以及HTTP/2的多路复用特性。gRPC基于HTTP/2和Protocol Buffers,利用高效的数据序列化和传输机制,实现高性能的远程调用。同时,文章还涉及了HTTP/2的header管理和gRPC的错误处理机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Chapter 4. gRP: Under the hood

RPC Flow

在这里插入图片描述

  1. client 使用生成的 stub 调用 getProduct 函数。
  2. client stub 使用编码消息创建一个 HTTP POST 请求。在 gRPC 中,所有的请求都是 HTTP POST请求,其 content-type 的前缀是 application/grpc。 客户端调用的远程函数作为一个单独的 HTTP Header 被发送。
  3. HTTP 请求消息通过网络被发送到 server 机器上。
  4. 当消息被服务器接收时,服务器检查消息的 header 来查看哪个服务函数需要被调用,并将消息移交给 service stub。
  5. service stub 将字节消息解析为语言指定的数据结构。
  6. 然后,使用解析的数据,service 对 getProduct 函数做本地调用。
  7. 来自 service 函数的响应被编码并发送回 client,response->encode->HTTP response on the wire。消息被解包,它的值被返回到等待的 client 进程。

Message Encoding Using Protocol Buffers

使用 protocol buffers 定义服务包含定义服务中的远程方法,和定义消息结构。

message ProductID {
	string value = 1;
} 

消息实体的编码表示由字段标识符(tag),后跟编码后的字段值组成。
在这里插入图片描述
Tag 由两部分组成:field index 和 wire type。field index 是在定义消息字段时赋值的唯一数字。wire type 基于 field type,它提供计算值长度的信息。
在这里插入图片描述在这里插入图片描述

Encoding Techniques
Varints

Varints 分配变长字节来表示一个值。
在这里插入图片描述

Signed integers

使用 zigzag 编码将有符号整数转换无符号整数,然后使用 Varints 对无符号整数进行编码。
在这里插入图片描述
负整数映射为奇数,正整数映射为偶数。

Nonvarint numbers

以定长字节表示数字值。64 位数据类型,fixed64,sfixed64 和 double。32 位数据类型,fixed32,sfixed32 和 float。

String type

string 类型是限定长度的 wire type,为 varint-encoded 的长度值后跟指定字节数的数据。string 值使用 UTF-8 字符编码方式。

Length-Prefixed Message Framing

gRPC 使用的 message-framing 技术称为 length-prefix framing,即先写入消息的长度,再写入消息本身。

在这里插入图片描述
消息长度为 4 字节,表示 gRPC 消息的大小至多 4 GB。

gRPC over HTTP/2

gPRC channel 本质是 HTTP/2 的连接;gRPC 远程调用被映射到 HTTP/2 的流中。
在这里插入图片描述

Request Message

在这里插入图片描述
Client 发送 Request Headers 标识 RPC 的开始,然后发送 Length-Prefixed-Message,最后发送 EOS 标识 RPC 请求结束。

在这里插入图片描述

  1. 定义 HTTP method。gRPC 总是使用 POST,表示请求使用目标资源处理 representation。
  2. 定义 HTTP scheme。如果启用 TLS(Transport Level Security),sheme 被设为 “https”,否则未 “http”。
  3. 定义 endpoint path。对于 gRPC 来说,为 “/”{service name}“/”{method name}。
  4. 定义 target URI 的 virtual hostname。
  5. 定义不兼容代理的检测。对于 gRPC,该值必须是 “trailers”。
  6. 定义调用超时。如果没有指定,服务器应当假设超时为无限时间。
  7. 定义 content-type。对于 gRPC,content-type 应当为 application/grpc。否则,服务会返回状态码 415 (Unsupported Media Type)。
  8. 定义消息压缩类型。可能的值为 identity,gzip,deflate,snappy,和 {custom}。
  9. 这是一个可选的 metadata。authorization metadata 被用于访问安全终端。

一些其他的需要注意的点:

  • 以 “:” 起始的 Header 被称为保留的 header,HTTP/2 要求保留 header 出现在其他 header 之前。
  • 在 gRPC 通讯中的传递的 headers 被分为两类:调用定义 header 和自定义 metadata。
  • Call-definition header HTTP/2 支持的预定义 header。它应当在自定义 metadata 之前发送。
  • 自定义 metadata 是任意的键值对,由应用层定义。当你定义自定义 metadata 时,你需要保证不使用以 grpc- 起始的 header。它们被保留由 gRPC core 使用。

client 先发送 request header,再发送 length-prefixed message(可以分为多个 frame),最后以 EOS 结束本次 HTTP 请求。
在这里插入图片描述

Response Message

Response Message 由三部分组成:Response Headers,Length-Prefixed Message 和 Trailers。
在这里插入图片描述
在这里插入图片描述

  1. 表明 HTTP 请求的状态。
  2. 定义消息压缩类型。可能的值为 identity,gzip,deflate,snappy,和 {custom}。
  3. 定义 content-type。对于 gRPC,content-type 应当为 application/grpc。

与 request header 类似,应用层定义的自定义 metadata 包含任意的键值对,它们能被设置到 response header 中。

发送 response header 后,会使用单独的一个或几个 HTTP/2 data frame 发送 length-prefixed 消息,但是最后一个 HTTP/2 data frame 不会设置 END_STREAM flag,它在另外一个称为 trailer 的 header 中设置。
在这里插入图片描述
最后,发送 trailers 来表示 response message 发送完成,它包含请求的 status code 和 status message。
在这里插入图片描述

  1. 定义 gRPC 状态码。
  2. 定义错误描述,这是可选的,仅在处理请求过程中发生错误才定义。

特定情况下,client 的请求调用可能会立刻失败,此时,server 仅发送 trailers 作为 response。它依然包含 gRPC status 和 status message,此外,它还包含其他的 header,因为只返回一个 HTTP/2 header。它包含 END_STREAM 和 END_HEADERS flags。

  • HTTP-Status->:status
  • Content-Type->content-type
  • Status->grpc-status
  • Status-Message->grpc-message

Understanding the Message Flow in gRPC Communication Patterns

Simple RPC

在这里插入图片描述

Server-streaming RPC

在这里插入图片描述

Client-streaming RPC

在这里插入图片描述

Bidirectional-streaming RPC

在这里插入图片描述

gRPC Implementation Architecture

在这里插入图片描述

Summary

gRPC 构建与 protocol buffer 和 HTTP/2 之上。

protocol buffer 是一个数据序列化协议,它生成的二进制 payload 较 json 格式更小且是强类型的。

HTTP/2 用于传输 protocol buffer 生成的二进制 payload。HTTP/2 是多路复用的,它支持在单个 TCP 连接上存在多个数据流。

const grpFilters = [...new Set(fcStatus.value.map(item => item.GRP))].map(value => ({ text: value, value })) 在运行此行语句时出现了如下的报错: ERROR Cannot read properties of null (reading 'map') TypeError: Cannot read properties of null (reading 'map') at setup (webpack-internal:///./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/views/FcStatusView.vue?vue&type=script&lang=js:46:51) at callWithErrorHandling (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:387:19) at setupStatefulComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:7161:25) at setupComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:7122:36) at mountComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4835:7) at processComponent (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4813:9) at patch (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:4488:11) at ReactiveEffect.componentUpdateFn [as fn] (webpack-internal:///./node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js:5011:9) at ReactiveEffect.run (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:323:19) at ReactiveEffect.runIfDirty (webpack-internal:///./node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js:359:12) 应该如何解决?
最新发布
03-26
### 处理 `java.lang.NumberFormatException` 异常 为了有效处理 `java.lang.NumberFormatException` 异常,在尝试将字符串转换为数字之前,应该先验证字符串的有效性。可以采用多种策略来实现这一点。 #### 使用 try-catch 块捕获异常 最直接的方法是在可能引发异常的地方使用 `try-catch` 结构。这样可以在发生异常时执行特定的操作而不是让程序崩溃[^2]。 ```java public class Main { public static void main(String[] args) { String strNumber = "NotANumber"; try { int number = Integer.parseInt(strNumber); System.out.println("Converted integer is: " + number); } catch (NumberFormatException e) { System.err.println("Error converting string to integer: Invalid format."); } } } ``` #### 预检查字符串格式 另一种更高效的方式是在调用解析函数前通过正则表达式或其他方式预检查字符串是否符合预期的数值模式[^4]。 ```java public class Main { private static final String NUMBER_PATTERN = "-?\\d+(\\.\\d+)?"; public static boolean isValidNumber(String strNum) { if (strNum == null || "".equals(strNum.trim())) return false; return strNum.matches(NUMBER_PATTERN); } public static void main(String[] args) { String strNumber = "123abc"; if (!isValidNumber(strNumber)) { System.err.println("Invalid input detected before conversion attempt."); } else { try { double num = Double.parseDouble(strNumber); System.out.println("Successfully converted value: " + num); } catch (NumberFormatException ex) { // This should not happen due to the pre-check. System.err.println("Unexpected error during parsing despite validation."); } } } } ``` 这两种方法都可以有效地防止因非法输入而导致的应用程序失败,并提供更好的用户体验和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值