Protocol Buffers 入门:为什么它比 JSON 小 60%,快了 5 倍?

发布时间:2026/10/21 11:44:37

Protocol Buffers 入门:为什么它比 JSON 小 60%,快了 5 倍? 整理旧电脑发现在待发布文章的文件夹下还躺着好几篇博客整理下也补发上来。本文是“Protocol Buffers 协议认识”系列的上篇面向初学者和中级开发者。读完本文你会理解 Protobuf 为什么快、为什么小、什么时候该用、什么时候不该用。下一篇将介绍在 Android开发中如何落地使用 Protocol Buffers。一、前言JSON 在过去十年里几乎成了“数据交换”的代名词。它直观、通用、调试友好——这些都是真实的优点。但也正因为太顺手很多开发者从未认真算过一笔账那些在 JSON 里反复出现的字段名、引号和括号在高频传输中到底占了多少带宽又消耗了多少解析时间Protocol Buffers简称 Protobuf来回答上面的问题它不是“另一个 JSON”而是一套完全不同的设计哲学用 schema 换效率用二进制换速度用字段编号换兼容性。本文从JSON边界讲起然后拆解 Protobuf 的”小“与”快“最后给出一张判断清单帮助大家知道什么时候可以使用 Protobuf。二、JSON 优势的边界JSON 的核心优势就是它的文本本质可以直接读、浏览器原生支持、几乎所有编程语言都有成熟的解析库。在接口调试、配置传递、对外 API 这些场景里JSON 的可读性是不可替代的。但可读和高效之间天然存在张力。我们来看一条 JSON 消息[{id:1,name:张三,email:ab.com},{id:2,name:李四,email:cd.com}]这条消息大约100字节但其中真正承载内容的字段值可能只占一半左右其余都是字段名、标点符号等。每传输一条信息这些结构性字符都要被完整地序列化、传输、再解析一遍。而实际开发中我们的字段名只会比该示例更长、更多、嵌套更深冗余比例进一步上升。user-test 是删除了标点符号、字段等。解析侧的代价同样存在。JSON 解析器需要扫描文本、识别语法边界、推断类型——1和1在解析路径上完全不同。无论是要一个字段还是全部解析器都得把整段文本走一遍。这种”边走边猜“的模式在高频场景下会成为不可忽视的开销。工作久了的朋友应该遇到过下面一个场景后端把email改成emailAddress——没有告诉前端你的 Gson/ kotlinx.serialization 在编译期没有报错等程序运行到手机上发现序列化失败、某个页面数据没有这也是 JSON 没有的能力消息结构无法保持向后和向前兼容。既然发现了问题那就想办法解决——Protobuf来了。三、Protobuf 是什么Protocol Buffers 是 Google 开发的一种语言无关、平台无关、可扩展的结构化数据序列化机制。它和 JSON 最根本的区别在于JSON 是自描述的Protobuf 不是它更快、更小、更简单。JSON 的一条消息自带字段名任何人拿到都能理解它的结构。Protobuf 的消息本身不包含字段名它只包含字段编号和二进制值。结构信息被提前抽取出来写在一个.proto文件里protobuf 的核心思想是契约优先Schema First先写一份.proto文件定义数据结构再用工具生成对应语言的代码。syntax proto3; message User { int32 id 1; string name 3; string email 2; }这个文件就是schema。你用它定义消息长什么样然后用protoc编译器把它生成目标语言的代码。等号后面的数字1、3、2叫字段编号field number是 Protobuf 里最重要的概念之一。⚠️ 字段编号不是顺序是身份标识示例中故意写成了name 3、email 2。编号一旦确定就永远不要更改和复用。四、拆解 Protobuf 为何又小又快本小节是文章重点。4.1 为什么小不存字段名只存编号JSON 把name:张三全存了。可 Protobuf 只存字段 3 是 string 类型用 1 个字节的 Tag 标记后跟值的长度和内容4.2 varint小数字只占 1 字节protobuf 用varint变长整数编码整数。规则很简单每 7 位打一组最高位第 8 位当【续传标志】——是 1 表示后面还有字节是 0 表示到此结束。举个具体例子数字123123 的二进制0111 1011 刚好 7 位没超 最高位补 0 → 0 1111011 0x7B123 128所以只占 1 个字节0x7B。再看大一点的300300 的二进制1 0010 1100 9 位超过 7 位要拆两组 从低位取 7 位001 01100 44 → 续传位 1 → 1 00101100 0xAC 剩下的高位 000 0010 2 → 续传位 0 → 0 0000010 0x02 所以 300 编码为AC 02 两个字节小端分组4.3 TLV字段变字节protobuf 每个字段按Tag-Length-Value组织string / bytes 等有 Length 段varint 等定长类型没有 Length但统称 TLV 思想。以User的name 张三为例假设name编号是 3wire type 2 表示 length-delimitedTag (字段编号 3) | wire_type (3 3) | 2 26 0x1A Length 张三 的 UTF-8 字节数假设 6 字节 0x06 Value 张三 的 UTF-8 编码 完整字节流片段1A 06 张三的 6 个字节再看整数字段id 123编号 1wire type 0 表示 varintTag (1 3) | 0 8 0x08 Value 123 的 varint 0x7B 字节流片段08 7B把整个User对象拼起来就是一连串紧凑的字节没有多余空格、没有引号、没有重复的键名。这就是又小又快的真相用编号代替名字 用变长整数压缩小数字 纯二进制无文本解析开销。五、一个 Java 最小闭环示例5.1 写.proto文件syntax proto3; option java_package org.example.demo; option java_multiple_files true; message User { int32 id 1; string name 3; string email 2; }代码解读syntax proto3声明使用 proto3 语法。java_package指定生成类的包名。java_multiple_files true让每个 message 生成独立的.java文件不设置的话所有类型会嵌套在一个外部类里。5.2 用protoc生成 Java 代码protoc--java_outsrc/main/java user.proto这条命令会生成User.java或按包路径组织。你需要把protobuf-java运行时依赖加进项目版本要等于或高于protoc的版本。输出目录是target/generated-sources/protobuf/java/com/example/demo/User.java如果使用 IDE如 Intellij IDEA可以利用 Maven 编译来生成User.java。5.3 构建、序列化、反序列化publicclassProtobufDemo{publicstaticvoidmain(String[]args)throwsException{// 构建消息必须走 BuilderUseruserUser.newBuilder().setId(1).setName(Alice).setEmail(aliceexample.com).build();// 序列化消息对象 - 二进制字节数组byte[]bytesuser.toByteArray();System.out.println(Serialized size: bytes.length bytes);// 反序列化二进制字节数组 - 消息对象UserparsedUser.parseFrom(bytes);System.out.println(Parsed name: parsed.getName());System.out.println(Parsed id: parsed.getId());}}六、版本兼容Protobuf 有一个 JSON 不容易做到的能力在消息结构演进时保持向后和向前兼容。向前兼容老 App 读新数据后端新增了字段phone老版本 App 的.proto里没有这个编号。反序列化时protobuf 看到不认识的字段编号直接忽略绝不会崩。向后兼容新 App 读老数据新 App 多了phone字段但老服务器返回的数据没有它。protobuf 给phone填默认值空串 / 0 / falseApp 正常跑。但这套兼容有着严格的纪律要求字段编号一旦使用永远不要修改编号是二进制流中识别字段的唯一标识改了编号等于换了字段的身份。永远不要复用已经删除的字段编号删除字段时应该用reserved把编号保留下来防止将来有人误用导致反序列化出静默错误。不要随意更改字段类型int32改成string这类变更在二进制层面是不兼容的会导致解析失败或数据损坏。七、何时使用Protobuf 就没有劣势吗当然有可读性差二进制流人眼无法阅读。Web/JS 原生不支持浏览器需要额外引入库。不适合人手改的配置文件运维等手动修改配置文件的场景如 YAML、JSON不要使用它。我们用几张清单来判断一个场景是否适合 Protobuf先看第一张#自检问题如果答案是结论1这条数据需要人直接打开看、手动改吗是别用 Protobuf2传输频率和体量值得为它引入工具链吗否JSON 更省事3结构会持续演进而不是推倒重写吗否Protobuf 的纪律成本收不回来如果三问都指向 Protobuf再用下面第二张表确认具体场景场景典型信号为什么划算RPC / 微服务通信服务间高频调用契约由团队自己掌控gRPC 默认 Protobuf契约与传输一体IM、实时推送、游戏同步消息量大、频率高、移动网络为主带宽和电量是硬约束体积收益直接兑现跨语言数据交换同一份数据要被 3 种以上语言消费一份.proto生成多语言代码消除手写解析漂移移动端网络请求与本地存储Android / iOS 端包体积和内存敏感Lite runtime 体积更小Proguard 友好八、总结Protobuf用可读性换效率用 schema 纪律换兼容性和代码生成带来的杠杆。它的“小”来自把字段名从传输流中拿掉、用字段编号做标识、用 Varint 压小整数。它的“快”来自解析器不需要猜类型、不需要扫描文本语法。它的兼容性来自一套严格的字段编号规则——规则遵守了演进就安全规则破坏了二进制层面不会给你警告。下一篇会介绍在 Android 平台如何使用 Protobuf 。九、参考资料GitHubhttps://github.com/protocolbuffers/protobufProtocolBuffer Tutorialshttps://developers.google.com/protocol-buffers/docs/tutorials?hlzh-cnProtocol Buffers 文档https://protobuf.com.cn/Protocol Buffers Java 示例https://protobuf.com.cn/getting-started/javatutorial/https://cloud.tencent.com/developer/article/2463651
延伸阅读

更多相关文章

2026/10/21 11:44:37

书写自我:基于心理学研究的自我认知建构

叙事的自我:通过记录建构自我认知与个人成长 引言 记忆具有显著的选择性和易塑性特征。人类的大脑并非一台客观记录现实的录像机,而是一个不断重构过往经验的叙述者。在认知心理学领域,Wilson 和 Ross(2003)的研究明确…

2026/10/21 11:44:37

你的空压机为什么费电?

摘要: 面对市面上琳琅满目的螺杆空压机,很多用户在搜索“永磁螺杆空压机哪家好”时感到困惑——尤其是老厂气压不足想换机、新厂房配套气源,又担心买到“电老虎”或故障停机拖垮产线。本文从能效、稳定性、服务响应三个维度,对比无…

2026/10/21 11:44:37

03 周郑交质

郑武公、庄公为平王卿士。 郑武公、郑庄公做周平王的卿士。王贰于虢,郑伯怨王。 周王对虢公另有心意(把政事分给虢公),郑伯怨恨周王。王曰:“无之。” 周王说:“没有这回事。”故周郑交质。 所以周、郑交换…

2026/10/21 12:40:48

LangChain + RAG实战:构建企业知识库问答系统的完整指南

做应用开发,总要面对一个尴尬:大模型看起来什么都懂,但一旦问到你们公司的报销制度、项目记录、售后口径,它就露馅了——要么不知道,要么编一个像模像样的答案。这也是这几年大模型落地时最常被追问的问题。RAG&#x…

2026/10/21 12:40:48

CANN框架下AMCT模型压缩实战:量化、剪枝与蒸馏全解

这两年做端侧模型部署的朋友应该都有同样的感受:模型性能越来越强,但算力、带宽和功耗的账越来越难算。一个动辄上百兆的模型,直接塞进设备基本不现实,于是量化、剪枝、知识蒸馏这几个词几乎成了部署前的必经流程。我第一次接触CA…

2026/10/21 12:40:48

昇腾CANN ops-nn算子库深度解析:从AI Core到融合算子与性能调优

从第一次把模型跑在昇腾设备上开始,我就一直在琢磨一件事:为什么同一个网络,在 GPU 上训练得好好的,迁移到昇腾上性能就差了一大截?后来追根溯源,问题几乎都出在算子这一层。昇腾算力真正落地靠的是 CANN 这…

2026/10/21 12:40:48

鲲鹏ARM架构部署GitLab全攻略:Docker安装、性能调优与踩坑实录

1. 为什么要在鲲鹏架构上折腾GitLab 第一次在鲲鹏服务器上装GitLab的人,大概率会经历一个"以为十分钟搞定,结果折腾一整天"的过程。原因很简单:GitLab官方提供的安装包和镜像,绝大多数是面向x86_64架构的,而…

2026/10/21 12:40:48

Docker根分区爆满?CentOS LVM在线扩容实战指南

1. 从一次告警说起:为什么容器主机的根分区总是不够用 凌晨两点,监控面板上那条代表磁盘使用率的曲线又一次顶到了95%的红线。登录到宿主机上一看, df -h 的输出里 /dev/mapper/centos-root 这个挂载点已经吃掉了将近全部空间&#xff0c…

2026/10/21 12:35:42

GB28181中SDP会话描述协议详解与对接排查指南

1. 从一个实际对接问题说起:为什么SDP值得单独拎出来讲但凡做过视频监控平台对接、流媒体信令交互、或者安防设备联网的同行,大概率都经历过这样的场景:设备注册上来了,信令也通了,但一到点播就黑屏,抓包一…

2026/10/21 4:53:08

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/21 0:00:35

交通流仿真实战:IDM跟驰与MOBIL换道模型参数调优与避坑指南

简介:这份资源是面向交通工程学习者与Python开发者的微观交通流仿真项目,核心实现智能驾驶模型(IDM)下的车辆跟驰与换道行为,可用于理解速度、密度与流量之间的动态关系,适合具备Python基础、希望深入交通模…

2026/10/21 0:00:35

揭穿智能体表面顺从:用追踪代码重建任务执行确定性

1. 表面顺从不是智能体的“礼貌”,而是任务执行链路上的隐性断点最近在调试一个跨平台长周期任务调度系统时,我反复遇到一种令人困惑的现象:智能体在用户指令发出后,几乎秒级响应“已收到”“正在处理”“请稍候”,UI上…

2026/10/21 0:00:35

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑