|
这两天看到netflix的技术博客,有两篇关于protobuf的field_mask功能使用。简单研究了下具体功能。这里做一下笔记。
背景
中台服务(Production service)管理着工作室的产品。对外提供了GetProduction接口,通过production_id返回商品的详细信息(format, schedule dates, scripts等等)。但是像产品的schedule和scripts信息,需要访问远端服务进行获取(也就是说schedule和scripts的获取成本很高,需要远端服务访问)。但对于有些请求,不关心schedule和scripts信息,此时对于Production service没必要访问远端。
问题
如何设计一个接口,能够同时满足:
1. 接口Pb结构简单明了
2. 对于调用方不感知的字段,可以跳过(减少服务压力) 解决
通过引入field_mask
import "google/protobuf/field_mask.proto";
// 产品的细节字段
message Production {
string id = 1;
string title = 2;
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
// ... more fields
}
// 请求的Pb结构
message GetProductionRequest {
string production_id = 1; // 调用方想要获取的商品id
google.protobuf.FieldMask field_mask = 2; // 调用方关注的商品字段名
}举例:调用方只关注title信息
客户端代码
GetProductionRequest CreateReq() {
GetProductionRequest req;
req.set_production_id("123321");
auto* field_mast_ptr = req.mutable_field_mask();
field_mast_ptr->add_paths("title"); // 设置只关注title字段
return req;
}
服务端
Production GetProduction(GetProductionRequest& req) {
auto& production_id = req.production_id();
Production ret = GetFromLocalDb(production_id); // 获取 title,format等基础信息
auto schedule_iter = std::find(req.field_mask().begin(),
req.field_mask().end(),
"schedule");
// 关注schedule,就进行远端调用
if (schedule_iter != req.field_mask().end()) {
}
// 因为ret中可能还有一些调用方不关注的字段
// 通过这个删除掉
// 由于field_mask里只有title,其他字段都会清空。也达到了节省带宽
FieldMaskUtil::TrimMessage(req.field_mask(), &ret);
}限制
很明显,其实就是强依赖字段名,如果涉及修改,字段名不能随意修改。否在就会失效。文章中提了几个解决办法,但其实最终的意思就是新建一个字段,并标记老字段废弃(pb提供了deprecated)。
message Production {
string id = 1;
string title = 2 [deprecated = true]; // use "title_name" field instead
ProductionFormat format = 3;
repeated ProductionScript scripts = 4;
ProductionSchedule schedule = 5;
string title_name = 6;
}
参考文档
1. protobuf的文档:
2. netflix博客两篇 |
|