• Google protobuf使用技巧和经验总结


    技巧 & 经验

    性能优化

    把repeated message结构尽可能摊平为基础类型的repeated字段

    基础类型的repeated字段,包含 repeated int32, int64, float,double,bool等,但不包含string、bytes、message

    比如:

    message Item {
        int32 id = 1;
        int32 score = 2;
    }
    
    message R {
        repeated Item items = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    改为下面的设计,会提升序列化和反序列效率

    message R {
        repeated int32 item_id = 1;
        repeated int32 item_score = 2;
    }
    
    • 1
    • 2
    • 3
    • 4

    原理是非string的基础类型的repeated字段,在申请内存时pb会申请连续线性大块内存,效率高;而message 的repeated字段,会按对象逐个去申请空间。

    善用arena管理内存

    • arena对基础类型,比如int32, int64, float,double,bool等管理效率优化明显
    • arena不会管理字符串类型的内存申请。

    用固定长度repeated uint32 替换字符串

    字符串是一种不定长的数据结构,内存管理方式成本较高。通过转换成repeated uint32类型,则可以获得更高效的管理。

    除此之外,repeated uint32 也支持由arena管理。

    善用Any类型

    假设3个网络服务的调用关系如下:
    A->B->C。
    其中存在某些pb结构仅会由B透传给C,而B不需要解析,则可以把这些pb放入定义为any类型的字段中。

    利用protobuf一些特性来规避陷阱

    良好的可扩展性 & 保留未定义字段

    良好的可扩展性使得protobuf更好地向后兼容。上游更新了proto,新增字段,下游虽然没有更新proto文件,但是新增的字段依然可以保留,来自上游的字段可以透传给下游。拼接下游请求的结构pb时,尽可能使用CopyFrom,避免把字段逐个set。

    使用编号定位存储的字段

    为了更好地向后兼容,应该避免修改proto文件中现有字段的名字、类型。需要修改时,通过追加新字段(字段编号增加),弃用旧字段的方式。

    故障相关

    protobuf被广泛使用,饱经业界考验,如果遇到问题,绝大多数还是自身软件设计的问题。遇到问题,首先不应该怀疑protobuf,应该把视角集中到去发现自身的系统设计缺陷中。

    一次内存泄露的故障排查

    现象:

    公司里一个c++网络服务中, PV较低时没有内存泄露;而PV较高,cpu idle降到30%以下,开始内存泄露,直到OOM。

    排查过程:

    用了 tcmalloc和gperf,逐步定位是protobuf 申请 repeated字段的空间,没有及时释放。repeated字段约1k~1w的规模。然后逐步缩小范围。

    结果:

    竟然是释放内存,都放到了一个线程中。当流量大时,单个线程计算能力成为瓶颈,内存释放变慢,表现为内存泄漏。


    转载请注明来源,原地址保持持续更新。
    博客首页:作程的技术博客
    文章标题:《Google protobuf使用技巧和经验总结》
    本文链接:https://it.zuocheng.net/google-protobuf-skills-experience-zh

  • 相关阅读:
    TodoList案例
    Python系列模块之标准库json详解
    CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)的内部网络结构有什么区别?
    178:vue+openlayers 加载多种形式Esri地图
    Python 测试框架 Pytest 的入门
    Dubbo(二):Dubbo 2.x 基础配置 Xml 方式、注解方式 和 高级特性
    【Java难点攻克】「大文件处理系列」让我们一起去挑战一下如何读取一个较大或者超大的数据文件
    关于刷题时使用数组的小注意事项
    二叉排序树查询删除结点和删除结点的父节点(代码实现) [Java]
    kubernetes之etcd基本操作
  • 原文地址:https://blog.csdn.net/Zuocheng_Liu/article/details/126611833