protobuf实现原理

news/2025/1/11 5:06:36/

文章目录

    • 一、前言
    • 二、概述
    • 三、数据存储方式:Varints
      • (一)原理
      • (二)举例
      • (三)缺点
    • 四、协议的数据结构
      • (一)原理
      • (二)举例

一、前言

最近刚刚从一家公司离职,在职的时候使用到了go语言的grpc库,了解了除了json之外的另一个专门用于远程调用的序列化工具protobuf。protobuf是Google开源的一款支持跨平台、语言中立的结构化数据描述和高性能序列化协议,此协议完全基于二进制,所以性能要远远高于JSON/XML。由于出色的传输性能因此常见于微服务之间的通讯,其中最为著名的是Google开源的 gRPC 框架,下面来谈一谈它的原理。

二、概述

  • protobuf将消息里的每个字段进行编码后,再利用T-L-V或者T-V的方式进行数据存储。
  • protobuf对于不同类型的数据会使用不同的编码和存储方式。
  • protobuf的编码和存储方式是其性能优越、数据体积小的原因。
    所以问题也就很明确了,只需要了解对于不同的数据类型,protobuf是怎么编码的,怎么存储的就可以了。

三、数据存储方式:Varints

(一)原理

Varints是一个变长保存数据的方法,在C++中一个整型数字通常使用4个字节来保存即int类型。但是对于Varints来说,小于128的数字可以使用一个字节来表示,而大于128的数字才会使用多个字节来表示。
下面来讲解它是怎么约束的:
在Varints编码中,它的每个字节的最高比特位有一定的含义,如果是1的话那么表示它后面的字节也是该数字的一部分,剩余的其他7个比特位才代表数字,这个思想和IP报文的分片挺相似的。所以就很容易理解为什么小于128的数字可以使用一个字节来表示了,因为第一位被占用了。

(二)举例

举两个例子:
表示65这个数字:
在这里插入图片描述
此时第一位为0,表示下面的字节和这个字节表示的数字不是同一个数字了。
表示300这个数字:
在这里插入图片描述
这里使用的是大端存储,高位低地址,低位高地址。第一个字节为1,表示它下一个字节存的数字和当前存的数字是同一个数字。

(三)缺点

这种存储方式对于小的数字比较友好,可以使用更少的字节数去存储,但对于大的数字就不太友好了。有的数字可能4个字节就可以搞定被生生存了5个字节。所以在protobuf中使用更小的数字才是效率更高的。
在协议的数据结构中,key使用的是varint编码,因此索引字段从1开始而不是负数,因为负数存的是补码通常占位比较多,影响了效率。

四、协议的数据结构

(一)原理

消息在经过序列化后会形成一个二进制数据流,流中数据为一系列的K-V对,Value怎么存上面已经介绍过了,这里介绍Key。
首先我们需要明确的是protobuf要存什么,一个是数据,也就是value,一个是key也就是索引字段,当我们使用protobuf定义一个message的时候通常是这样的:

message mystruct
{int32 a=1;int32 b=2;
}

其中1和2表示的是索引字段,它们具体的值就是value。
key除了作为value的索引之外,还需要指定value的编码格式,注意这里key使用的是varint的编码格式,但是不代表数据就使用该格式。
key值的计算公式为: (field_number << 3) | wire_type,其中field_number为索引字段,wire_type表示的是数据的格式,它的格式分五种:
在这里插入图片描述
其实就只有五种,所以我们就知道了为什么它向左移动三位来为存放数据类型腾出空间。

(二)举例

举一个简单的例子:

message Test1 {required int32 a = 1;
}

通过查表可以知道,int32类型即该字段是使用varint编码格式来存储的,所以计算key为:
(1<<3)|0
同时由于存储key使用的是varint编码,因此第一位为结束符,这里的索引使用一个字节就可以了,因此结束符是0:
在这里插入图片描述
假设要传入的a的值是1,则a使用varint编码表示为:
在这里插入图片描述
此时就弄出来了一个字段的kv结构。而一个message有很多个字段,它们的排列是线性的:
在这里插入图片描述


http://www.ppmy.cn/news/297388.html

相关文章

NLP——part of speech (POS)中的隐马尔可夫模型 + Viterbi 算法

文章目录 POS隐马尔可夫模型计算简介转移概率矩阵&#xff08;Transition matrix&#xff09;观察矩阵&#xff08;Observation / emission Matrix&#xff09;预测 predictionVitervi 算法练习 POS 词性标注&#xff08;Part-of-Speech Tagging&#xff0c;POS Tagging&#…

虚拟ip设置 - Keepalived详解

1. ubuntu安装keepalived&#xff08;需要偏移的机器&#xff09; rootubuntu:~# apt install keepalived2. 编写配置文件/etc/keepalived/keepalived.conf&#xff08;需要偏移的机器&#xff09; rootubuntu:~# cd /etc/keepalivedrootubuntu:/etc/keepalived# vi keepaliv…

数据库实验七(SQL Server SSMS)

实验要求 运行环境 SQL Server 2022SQL Server Management Studio Management Studio 19 本实验的全部SQL脚本 -- 第一题 create function func1(coursename char(30)) -- 定义函数 returns float as begindeclare avg_score floatselect avg_score avg(score) from sc, cw…

keepalived配置虚拟IP

YUM安装 # yum安装 yum -y install keepalived # 查看安装版本 rpm -qa keepalived # 查看安装路径 rpm -ql keepalived或是使用源码安装 到这里下载 https://www.keepalived.org/download.html # 安装依赖 yum -y install gcc openssl-devel libnfnetlink-devel 下载源码包…

IP反查域名

IP反查域名 ip反查域名的三种方法&#xff0c;方法有很多&#xff0c;我这边只描述三种&#xff0c;也算是两种 1&#xff0c;在线网站 http://stool.chinaz.com/same 2&#xff0c;在线网站 https://site.ip138.com/ 3&#xff0c;工具 https://github.com/Sma11New/ip2domain…

IP地址的CIDR格式

将IP地址分为A类、B类、C类后&#xff0c;会造成IP地址的部分浪费。例如&#xff0c;一些连续的IP地址&#xff0c;一部分属于A类地址&#xff0c;另一部分属于B类地址。为了使这些地址聚合以方便管理&#xff0c;出现了CIDR&#xff08;无类域间路由&#xff09;。 无类域间路…

c# Linq操作DataTable

转载&#xff1a;c# Linq操作DataTable_lcawen的专栏-CSDN博客在平时的工作中&#xff0c;可能有很多情况下要对DataTable的里面的数据进行处理&#xff0c;最简单的例子如&#xff1a;对DataTable中的某个字段进行排序&#xff0c;根据条件筛选DataTable中的数据。。。&#x…

ip地址转换省市

前言 最近开发一个支付系统&#xff0c;为了避免上游风控&#xff08;路由规则限制&#xff09;&#xff0c;需要根据请求ip解析到对应物理地域信息&#xff0c;从而匹配到对应的地域商户&#xff0c;解决跨域消费问题。即将线上消费包装成线下消费。 实例&#xff1a;支付宝…