上一讲介绍的 HTTP/2 协议在编码上拥有非常高的空间利用率,这一讲我们看看,相比其中的 HPACK 编码技术,Protobuf 又是通过哪些新招式进一步提升编码效率的。
Google 在 2008 年推出的 Protobuf,是一个针对具体编程语言的编解码工具。它面向 Windows、Linux 等多种平台,也支持 Java、Python、Golang、C++、Javascript 等多种面向对象编程语言。使用 Protobuf 编码消息速度很快,消耗的 CPU 计算力也不多,而且编码后的字符流体积远远小于 JSON 等格式,能够大量节约昂贵的带宽,因此 gRPC 也把 Protobuf 作为底层的编解码协议。
然而,很多同学并不清楚 Protobuf 到底是怎样做到这一点的。这样,当你希望通过更换通讯协议这个高成本手段,提升整个分布式系统的性能时,面对可供选择的众多通讯协议,仅凭第三方的性能测试报告,你仍将难以作出抉择。
而且,面对分布式系统中的疑难杂症,往往需要通过分析抓取到的网络报文,确定到底是哪个组件出现了问题。可是由于 Protobuf 编码太过紧凑,即使对照着 Proto 消息格式文件,在不清楚编码逻辑时,你也很难解析出消息内容。
下面,我们将基于上一讲介绍过的 HPACK 编码技术,看看 Protobuf 是怎样进一步缩减编码体积的。
怎样用最少的空间编码字段名?
消息由多个名、值对组成,比如 HTTP 请求中,头部 Host: www.taohui.pub 就是一个名值对,其中,Host 是字段名称,而 www.taohui.pub 是字段值。我们先来看 Protobuf 如何编码字段名。
对于多达几十字节的 HTTP 头部,HTTP/2 静态表仅用一个数字来表示,其中,映射数字与字符串对应关系的表格,被写死在 HTTP/2 实现框架中。这样的编码效率非常高,但通用的 HTTP/2 框架只能将 61 个最常用的 HTTP 头部映射为数字,它能发挥出的作用很有限。
动态表可以让更多的 HTTP 头部编码为数字,在上一讲的例子中,动态表将 Host 头部减少了 96% 的体积,效果