谈谈HTTP/2与gRPC之间的关系
我对于HTTP/2.0的理解源于
- RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
- RFC 7541: HPACK: Header Compression for HTTP/2
对gRPC on HTTP/2的理解基于
在读本文前需要了解HTTP/2的相关知识,可以看我写的HTTP与HTTP2
废话不多说,现在开始。
gRPC
gRPC(协议)是一个RPC协议,作为一个基本的RPC协议,需要传输哪些数据?
- 请求部分
- 服务名(Service Name) :标识远程服务的位置。
- 方法名(Method Name) :标识在远程服务上调用的方法。
- 参数(Parameters) :传递给远程服务的方法所需的数据。
- 响应部分
- 返回值(Result) :远程服务方法的执行结果。
- 错误信息(Error Information) :如果服务调用失败,返回相关信息。
作为一个优秀的RPC协议,还需要传输哪些数据?
- 元数据
- 重试机制相关数据
- 安全相关数据
- 压缩相关数据
以上数据除了请求参数和返回值是在http body,安全是在TLS和header,其他都是在http header中实现的。
gRPC request
Request → Request-Headers *Length-Prefixed-Message EOS
- Request-Headers:这是请求头,包含了元数据(metadata),如认证信息、内容类型等。这些头部信息帮助服务器了解即将接收的数据以及如何处理它。
- *Length-Prefixed-Message:这表示长度前缀的消息体,可以有零个或多个。每个消息体前面都有一个长度字段,指明接下来的消息体的字节长度。这种方式有助于解析器知道何时读取完一条消息并开始下一条消息。
- EOS (End of Stream):结束标志,表示请求消息流的结束。在HTTP/2中,这是一个特殊的帧,用来通知接收方没有更多的数据将被发送。
Request-Headers
在 http2 眼中 Request-Headers 是由 HEADERS & CONTINUATION frames组成
Request-Headers → Call-Definition *Custom-Metadata
Call-Definition → Method Scheme Path TE [Authority] [Timeout] Content-Type [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent]
其中method,scheme,path,authority都是h2的伪头部字段
其他比较常用的如下
- Content-Type = "content-type: application/grpc" [("+proto" / "+json" / {custom})]
- Content-Coding → "identity" / "gzip" / "deflate" / "snappy" / {custom}
- Timeout → "grpc-timeout" TimeoutValue TimeoutUnit
- TimeoutValue → {8位正整数}
- TimeoutUnit → Hour(H) / Minute(M) / Second(S) / Millisecond(m) / Microsecond(u) / Nanosecond(n)
应用程序可以自由选择其他任何名称作为自定义元数据的键名,只要不以 grpc- 开头即可。
所有以 grpc- 开头但未在当前规范中列出的头部字段被保留给未来的 gRPC 使用,应用程序不应使用这些保留字段作为自定义元数据
Length-Prefixed-Message
由data帧组成
- Length-Prefixed-Message → Compressed-Flag Message-Length Message
- Compressed-Flag → 0 / 1 ; encoded as 1 byte unsigned integer
- Message-Length →
{length of Message}
; encoded as 4 byte unsigned integer (big endian) - Message →
*{binary octet}
压缩标志值为1表示使用消息编码头声明的机制压缩消息的二进制八位字节序列。值为0表示没有发生消息字节的编码。 压缩上下文不会在消息边界上维护,实现必须为流中的每条消息创建一个新的上下文。如果省略消息编码头,则压缩标志必须为0。
对于请求,EOS(流结束)由最后接收到的DATA帧上的END_STREAM标志表示。在请求流需要关闭但没有数据需要发送的情况下,实现必须发送一个设置了此标志的空DATA帧。
为什么需要 Length-Prefixed-Message ?
我们先看看h1是怎么表示请求长度的,大家都知道h1是使用 content-length
表示body长度。
然后我们看一下grpc的header,根本没有content-length
! 这是因为h2是使用END_STREAM
标识符表示流结束。这样就知道了body长度。但是在grpc的流式传输中,一次请求/响应可能会发送多个对象,此时就需要用到 Length-Prefixed-Message
标明每一个数据的长度
gRPC response
Response → (Response-Headers *Length-Prefixed-Message Trailers) / Trailers-Only
Response-Headers & Trailers-Only都在单个HTTP2 HEADERS帧块中交付
通信模式
gRPC有四种通信模式
- 一元RPC(Unary RPC) :标准的请求-响应模式。
c -HEADER-FRAME-> s
c <-HEADER-FRAME-s
c -DATA-FRAME-> s
c <-DATA-FRAME-s
- 服务端流式RPC(Server-side Streaming RPC) :客户端发送一个请求,服务器返回一系列消息。
c -HEADER-FRAME-> s
c <-HEADER-FRAME-s
c -DATA-FRAME-> s
c <-DATA-FRAME-s
c <-DATA-FRAME-s
c <-DATA-FRAME-s
- 客户端流式RPC(Client-side Streaming RPC) :客户端发送一系列消息,服务器返回一个响应。
c -HEADER-FRAME-> s
c <-HEADER-FRAME-s
c -DATA-FRAME-> s
c -DATA-FRAME-> s
c -DATA-FRAME-> s
c -DATA-FRAME[END_STREAM] -> s
c <-DATA-FRAME-s
- 双向流式RPC(Bidirectional Streaming RPC) :客户端和服务端都可以随时发送消息,形成一个双向流。
c -HEADER-FRAME-> s
c <-HEADER-FRAME-s
c -DATA-FRAME-> s
s -DATA-FRAME-> c
c -DATA-FRAME-> s
s -DATA-FRAME-> c
c -DATA-FRAME-> s
s -DATA-FRAME-> c
c -DATA-FRAME[END_STREAM] -> s
s -DATA-FRAME[END_STREAM] -> c
http/2 在官方文档中规定了两种通信模式
- 请求-响应(Request-Response)
- 服务器推送(Server Push):服务器可以在客户端发起请求之前,主动将可能用到的资源推送给客户端。
很明显
- UNARY -> Request-Response
但是
- Server-side Streaming RPC -> ?
- Client-side Streaming RPC -> ?
- Bidirectional Streaming RPC -> ?
http/2其实不只有两种通信模式,http/2 没有严格规定通信模式,规定这两种只是为了web使用规范。 http/2实际上规定的是多路复用(Multiplexing) 二进制分帧(Binary Framing) 流控制(Flow Control) 等机制
HTTP/2本身确实没有直接支持像gRPC那样的双向流式RPC(Bidirectional Streaming RPC)模式。HTTP/2提供的是基础的传输层能力,如多路复用、头部压缩、流控制等,但它并没有定义复杂的RPC模式或流式交互的具体实现。
h2为grpc提供了传输层的能力,grpc通过编排,管理帧的发送实现
- UNARY
- CLIENT_STREAMING
- SERVER_STREAMING
- BIDI_STREAMING
HTTP/2
以下仅代表我个人观点
HTTP/2 是应用层协议,但设计上部分借鉴了传输层的理念
- 网络层次划分视角:
- 根据 OSI 模型和 TCP/IP 体系结构,HTTP 协议,包括 HTTP/2,毫无疑问是应用层协议。它直接面向用户的应用程序,为它们提供数据通信的接口和协议框架,例如浏览器通过 HTTP 向服务器请求网页内容。
- 传输特性借鉴方面:
- 多路复用(Multiplexing) :HTTP/2 引入了多路复用(Multiplexing)技术,多个请求和响应可以在同一个连接上同时传输,这类似于传输层的多路复用(如 TCP 的多路复用特性)。但它是在应用层实现这一功能,使得应用层的请求 - 响应能够在逻辑上并行传输,而不需要像 HTTP/1.x 那样为每个请求建立新的连接。
- 流控制机制(Flow Control) :HTTP/2 提供了流控制机制,允许客户端和服务器控制数据流的速率,以防止发送方发送过快导致接收方缓冲区溢出。这与传输层协议(如 TCP)的流量控制机制有些类似,也是在应用层层面实现了类似的网络流量管理功能。
- 二进制分帧(Binary Framing) :HTTP/2 将数据分割成二进制帧(Frames),每帧都有自己的类型、标志和内容。这种分帧机制也有点类似于传输层协议对数据的封装和分割方式,能够在应用层对数据进行更细粒度的管理和传输。
h2给grpc一个环境,让grpc管理帧传输
HTTP/2 是 gRPC 的底层传输协议。gRPC 利用了 HTTP/2 的多个特性来实现高效的通信,例如:
- 多路复用(Multiplexing) :gRPC 使用 HTTP/2 的多路复用功能,允许多个 RPC 调用通过同一个 TCP 连接并行传输。这减少了连接的建立和关闭开销,提高了性能。
- 二进制分帧(Binary Framing) :HTTP/2 的二进制分帧机制使得 gRPC 能够更高效地传输数据。它将数据分割成更小的帧,每个帧都有自己的类型、标志和内容,这使得数据的传输更加有序和可靠。
- 流控制(Flow Control) :gRPC 借助 HTTP/2 的流控制机制来管理数据的传输速率。客户端和服务器可以通过调整流的窗口大小来控制数据的发送速度,防止发送方发送过快导致接收方缓冲区溢出。