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;
}

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

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

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

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

善用arena管理内存

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

善用Any类型

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

protobuf一些特性

良好的可扩展性

  • 保留未定义字段

设计优化

故障相关

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

一次内存泄露的故障排查

现象:

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

排查过程:

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

结果:

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

https://www.cnblogs.com/zgwu/p/10403939.html

发表评论

您的电子邮箱地址不会被公开。