从文本到二进制:HTTP/2 不止于性能,更是对 HTTP/1 核心语义的传承与革新
云原生计算基金会(Cloud Native Computing Foundation,CNCF)是一个非盈利的开源组织,专注于推动云原生计算的发展和标准化。而 gRPC(Google Remote Procedure Call)是由 Google 发起并开源的高性能、跨语言 RPC 框架。2017 年,Google 将 gRPC 项目捐赠给了 CNCF,使其成为云原生生态的核心组件之一。gRPC 与 Kubernetes(容器编排)、Prometheus(监控)、Istio(服务网格)等 CNCF 项目深度集成,广泛应用于微服务架构和云原生应用中,其重要性随着云原生理念的普及而日益凸显。gRPC 巧妙地结合了 ProtoBuf、HTTP/2 等成熟技术,为上述 RPC 三大问题提供了全面且标准化的解决方案。1)数据表示:默认采用 ProtoBuf 作为其 IDL 和高效的二进制序列化方案。2)数据传递:建立在 HTTP/2 协议之上,利用其多路复用、流控、头部压缩等特性实现高效网络通信。3)方法约定:通过 ProtoBuf IDL (.proto 文件) 定义服务接口和消息结构。
HTTP/2 协议

HTTP/2 是 HTTP/1.1 的重大升级版,其设计源于 Google 的 SPDY 协议,并于 2015 年正式成为标准(RFC 7540)。HTTP/1.1 虽应用广泛,但其固有的性能瓶颈——如队头阻塞(Head-of-Line Blocking)、较高的连接建立延迟、低效的文本头部传输——已难以满足现代 Web 应用对高性能、低延迟的需求。HTTP/2 旨在克服这些问题,显著提升传输效率和用户体验。与 HTTP/1.1 的纯文本传输不同,HTTP/2 引入了二进制分帧层 (Binary Framing Layer)。所有 HTTP 消息(请求/响应)都被封装成一个个二进制编码的帧 (Frame) 进行传输。这种设计不仅提高了处理效率和健壮性(解析二进制比文本更快更不容易出错),还为多路复用(Multiplexing)、头部压缩(Header Compression)和服务器推送(Server Push)等高级特性奠定了基础。HTTP/2 的核心架构包含以下几个关键概念。1)Connection(连接):一个 TCP 连接支持多个并发 Stream,减少了 HTTP/1.1 中多个 TCP 连接的开销和延迟。2)Stream(流):独立的双向通信通道,用于传输一条或多条 Message,避免了队头阻塞。3)Message(消息):对应 HTTP/1.1 的请求或响应,由一个或多个 Frame 组成,使数据传输更灵活。4)Frame(帧):最小的通信单位,采用二进制格式,包含元数据和有效载荷,用于客户端与服务器间的信息传递。

帧结构
帧是一种长度前缀消息(Length-Prefixed-Message)。帧以固定的 9 字节作为帧头,后面跟着变长的帧载荷(Frame Payload),帧头包括如下公共字段:Type、Length、Flags, Stream Identifier。
HTTP/2 协议定义了 10 种不同类型的帧(Frame),其中通用格式包含以下几个关键类型,这些类型共同定义了帧的行为和内容。1)Length(长度):表示帧载荷(Frame Payload)的长度,以字节为单位。其最大长度为 2^14(即 16384 字节),不包括帧头的 9 个字节。2)Type(类型):用于标识帧的类型。其中,DATA 帧和 HEADERS 帧,分别对应于 HTTP/1.1 中的数据和头部信息。其他帧类型还包括 SETTINGS、PRIORITY、RST_STREAM 等,用于实现协议的各种高级特性。3)Flags(标志):该字段包含一组标志位,用于传递帧的附加控制信息。常用的标志位包括: END_HEADERS:表示当前帧是头数据(Headers)的最后一帧,相当于 HTTP/1.1 中头信息结束后的空行(“\r\n”);END_STREAM:表示当前帧是流(Stream)中最后一个帧,标志着单方向数据传输的结束(End of Stream, EOS),相当于 HTTP/1.1 中分块传输编码(Chunked Encoding)的结束标志(“0\r\n\r\n”);PRIORITY:用于指示流的优先级,帮助服务器和客户端优化资源分配。4)R(保留字段):该字段为保留位,目前未使用,必须设置为 0。5)Stream Identifier(流标识符):用于标识帧所属的流(Stream)。每个流都有一个唯一的标识符,用于在同一个 TCP 连接中区分不同的并发流。流标识符的长度为 31 位,其中客户端发起的流使用奇数标识符,服务器发起的流使用偶数标识符。
消息的语义兼容性
HTTP/2 协议与 HTTP/1 尽可能保持兼容。从应用程序的角度来看,协议的功能基本没有变化。为了实现这一点,HTTP/1 的所有请求和响应语义被保留,虽然传达那些语义的语法已经改变。HTTP/1 使用消息起始行(start-line)来传达目标 URI,请求方法和响应的状态代码,而 HTTP/2 为此使用以“:”字符开头的特殊字段(pseudo-header)来达到相同的目的。

可以看到在第一个请求中,前两个头通常类似与 HTTP/1。
现在被拆分为一个标题框。
而其余的头则大致相同,都是 lower-case 字符。HTTP/2 尝试尽可能地最小化有效载荷大小。它将压缩与前一个请求中相同的头。在 HTTP/1 中,一个连续的请求看起来像是针对不同资源的初始请求。
而在 HTTP/2 中,对同一服务器的连续请求只需要:path 头部信息。
因为所有其他头部信息都被标记并压缩缓存,并且可以通过“索引”进行还原。
未完待续
很高兴与你相遇!如果你喜欢本文内容,记得关注哦!
版权声明: 本文为 InfoQ 作者【poemyang】的原创文章。
原文链接:【http://xie.infoq.cn/article/597409403f91b77a0d7c87e76】。文章转载请联系作者。
评论