热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

protobuf使用心得:解析与编码陷阱

本文记录了一次在广告系统中使用protobuf进行数据交换时遇到的问题及其解决过程。通过这次经历,我们将探讨protobuf的特性和编码机制,帮助开发者避免类似的陷阱。

da6b5c36a6e6d368d04c4bbc6afacd9e.png

本文旨在分享在广告系统开发中使用protobuf时遇到的一个具体问题及其解决方案。通过详细分析,希望能帮助读者更好地理解和应用protobuf。


在高性能需求的广告系统中,毫秒级的延迟优化至关重要。为了提高效率,我们选择了protobuf作为与外部媒体通信的数据格式,相较于JSON和XML,它能显著减少编解码时间和网络传输成本。然而,这种高效也伴随着一定的不便,如无法直接通过文本编辑器查看或修改数据,且问题排查难度增加。


- 遇到的问题 -

7月,一家媒体提出希望一次请求能获取多条广告,以便更好地适应信息流场景。为此,我们在Impression类型中添加了一个ads_count字段,用于指定所需广告的数量。按照常规流程更新了.proto文件,并生成了新的Go语言代码。然而,无论媒体请求中填写的具体数值如何,我们始终只能解码出ads_count为1的结果。


- 问题排查 -

鉴于我们的代码已经过测试,能够正确处理ads_count,初步怀疑问题出在媒体的请求上。通过录制并保存请求至req.pb文件,使用protoc --decode-raw命令尝试解码,但结果难以解读。随后,利用已知的.proto文件进行更精确的解码,发现了一个未在定义中出现的字段10: 3,这提示我们双方的.proto文件存在差异。


- 解决方案 -

经过与媒体的沟通确认,他们确实曾在ads_count之前添加了另一个字段。调整我们的.proto文件,将ads_count的序号改为10,重新编译并测试,问题得以解决。


- 编码机制简介 -

为加深理解,这里简要介绍protobuf的编码机制。每个字段在编码时会根据其序号和类型生成一个键值对,其中键由字段序号和类型标识组成,值则是实际的数据。例如,对于简单的Test1类型:

message Test1 {  optional int32 a = 1;}

当给a赋值150并序列化时,会生成三个字节的数据:08 96 01。首字节08的二进制形式为0000 1000,其中最低三位000表示这是一个varint类型,接下来四位0001表示字段序号1,最高位0表示这是最后一个字节。后续两个字节96 01则表示了实际的值150,遵循varint的小端存储规则。


- 关于负整数的编码 -

对于负整数,protobuf采用了特殊的ZigZag编码方式,以确保较小的负数也能被高效编码。这种方式通过交替使用正负数来表示连续的整数,从而实现更紧凑的编码。


- 结语 -

通过这次经历,我们不仅解决了实际问题,还深入理解了protobuf的工作原理。更多关于字符串、嵌套类型及数组的编码细节,建议参考官方文档。

最后,留给大家一个小练习:下面的编码数据表示了什么?12 03 36 36 36


推荐阅读:

  • 《程序员面试指南:从面试官角度看问题》
  • 《Go服务性能优化案例:内存激增问题的解决》
  • 《技术交流中的日志问题与沟通技巧》
  • 《C++面试难题解析》

5295a4be53445f8c560ef345ccbc5257.png


推荐阅读
author-avatar
呼吸乱了的声音_648
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有