如何用Protobuf 3高效处理镜像与增量更新?无需全字段设可选
Protobuf 3 无需全字段可选的增量更新实现方案
原消息定义
message Price { double bid = 1; double ask = 2; double last = 3; double tick = 4; int64 bidQty = 5; int64 askQty = 6; string tradingPhase = 7; // ... other fields }
针对你提出的需求——首次发送完整消息镜像,后续仅收发修改过的字段实现增量更新,且无需将原消息所有字段定义为可选——存在两种高效的处理方案:
方案一:使用 FieldMask 结合消息合并(官方推荐)
这是Google官方主推的增量更新方案,完全不需要修改原Price消息的字段定义:
定义更新请求消息
引入官方的field_mask.proto,新增一个包含更新字段和掩码的请求消息:import "google/protobuf/field_mask.proto"; message PriceUpdateRequest { Price updated_fields = 1; google.protobuf.FieldMask field_mask = 2; }发送方操作
- 构造一个仅填充了本次修改字段的
Price实例(比如只改了bid和bidQty,就只给这两个字段赋值) - 在
field_mask中列出本次更新的字段名(示例:paths: ["bid", "bidQty"]) - 发送
PriceUpdateRequest即可
- 构造一个仅填充了本次修改字段的
接收方操作
- 保留首次接收的完整
Price实例作为基准 - 使用Protobuf提供的FieldMask合并工具(不同语言对应工具不同:Java用
FieldMaskUtil.merge(),Go用proto.Merge()配合字段掩码过滤),只将field_mask指定的字段从updated_fields合并到基准实例中
- 保留首次接收的完整
这种方案的优势是复用原消息结构,无需修改原有字段属性,且通过掩码明确标记更新范围,避免字段默认值带来的歧义。
方案二:自定义增量更新消息
如果不想依赖官方的FieldMask,可以单独定义一个仅包含可选字段的增量消息:
message PriceDelta { optional double bid = 1; optional double ask = 2; optional double last = 3; optional double tick = 4; optional int64 bidQty = 5; optional int64 askQty = 6; optional string tradingPhase = 7; // ... 对应原Price的其他字段,全部设为optional }
- 发送方:每次只填充本次修改过的字段,发送
PriceDelta - 接收方:通过
has_xxx()方法(Protobuf 3对optional字段支持该方法)检查PriceDelta中存在的字段,将对应值更新到基准Price实例中
这个方案逻辑直观,不需要依赖外部proto文件,但需要维护一个与原消息字段同步的增量消息,字段变更时需同时更新两个定义。
注意
Protobuf 3中如果使用包装类型(如google.protobuf.DoubleValue)也能实现类似Protobuf 2的字段存在性检查,但这需要修改原消息的字段类型,不符合你“无需将所有字段定义为可选”的要求,因此不推荐。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

