找回密码
 立即注册
查看: 500|回复: 3

浅谈protobuf

[复制链接]
发表于 2021-12-13 20:29 | 显示全部楼层 |阅读模式
1. protobuf是什么?

1.1 protobuf概述

protobuf是Google公司提出的一种轻便高效的结构化数据存储格式,常用于结构化数据的序列化,具有语言无关、平台无关、可扩展性特性,常用于通讯协议、服务端数据交换场景,github地址:https://github.com/protocolbuffers/protobuf


protobuf的核心内容包括:

  • 定义消息:消息的结构体,以message标识。
  • 定义接口:接口路径和参数,以service标识。
通过protobuf提供的机制,服务端与服务端之间只需要关注接口方法名(service)和参数(message)即可通信,而不需关注繁琐的链路协议和字段解析,极大降低了服务端的设计开发成本。
1.2 protobuf使用案例

假设有个服务端程序SSR,期望对外提供一个注册接口,调用方传入手机号、姓名、邮箱三个信息,其中邮箱是选填的,那通过protobuf如何来实现接口定义呢?

  • step1: 定义服务名SSR和方法名register
service SSR {
    rpc register(RegisterRequest) returns (RegisterResponse);
};

  • step2: 定义接口参数和约束
message RegisterRequest {
    required string name = 1; // 姓名
    required string tel = 2; // 手机号
    optional string email = 3; // 邮箱:可选
};
message RegisterResponse {
    required int code = 1; // 错误码
    optional string err_msg = 2; // 错误信息
};

  • step3: 使用protoc生成语言相关的协议代码
// for golang
protoc -I . -I /usr/local/include -I $(GOPATH)/src --go_out=. ssr.proto

// for cpp
protoc -I . -I /usr/local/include --cpp_out=. ssr.proto利用官方提供的protoc生成语言无关的协议代码,比如golang、C++、python等等

  • step4:实现protobuf定义的接口
class SsrImpl : public proto::SSR {
    void register(::google::protobuf::RpcController* controller,
                    const proto::RegisterRequest* request,
                    proto::RegisterResponse* response,
                    ::google::protobuf::Closure* done);
}

  • step5:通过rpc框架注册Service & 实现业务逻辑
// 比如baidu-rpc框架为例
auto ssr = new baidu::rpc::Server();
ssr->AddService(new SsrImpl(), baidu::rpc::SERVER_DOESNT_OWN_SERVICE);通过protobuf我们可以低成本的定义调用接口,并且无需关注繁琐的序列化过程,大大降低了服务端的开发设计成本。
1.3 protobuf延伸知识

为了支持复杂数据结构和实现对数据的种种约束,protobuf内置了自己的一套规则和语法,详细可以参考:https://developers.google.com/protocol-buffers/docs/overview
在一些特殊场景需求时,可以查阅protobuf开发者文档。
2. protobuf vs JSON vs flatbuf

数据交换除了使用protobuf外,还可以使用JSON、flatbuf等,这里简单介绍一下各自的优缺点和适用场景。
protobuf

  • 优势:

    • 类型安全
    • 易用性好
    • 序列化/反序列性能好
    • 兼容性好
    • 不仅可以定义结构体,还可以定义rpc服务接口

  • 劣势:

    • 可读性较差:没有schema的情况下,难以阅读和编辑。
    • 灵活性较差:无法动态修改schema。

json: https://www.json.org/json-zh.html

  • 优势:

    • 可读性好:方便理解和编辑
    • 易用性好:使用简单
    • 灵活性好:支持动态修改schema

  • 劣势:

    • 序列化/反序列化性能差
    • 编码问题导致解析失败之类的

flatbuf: https://google.github.io/flatbuffers/

  • 优势:

    • 灵活性好
    • 性能好:序列化/反序列化几乎无耗时、高效的内存使用和读取速度。
    • 占用内存小

  • 劣势:

    • 可读性差
    • 易用性差:使用成本高,接口较为复杂

序列化/反序列化性能对比图:(来源于 https://codeburst.io/json-vs-protocol-buffers-vs-flatbuffers-a4247f8bda6f)




各自的应用场景,可以参看图:


简单总结:

  • rpc场景定义服务接口使用protobuf。(开发者友好 & 更好的性能)
  • 高频序列化/反序列化场景 & 期望灵活schema则使用flatbuf。(灵活的schema & 更好的性能)
  • 关注可读性&开发成本则使用JSON。(开发者友好 & 灵活的schema)
3. protobuf坑和小技巧


  • 字符串如果包含非英文字符,建议使用bytes字段:https://developers.google.com/protocol-buffers/docs/proto#scalar
  • 已有字段的field number不要修改:https://developers.google.com/protocol-buffers/docs/proto#assigning_field_numbers
  • 慎用required字段,容易造成不兼容的隐患(既不能删,又不能加):https://stackoverflow.com/questions/31801257/why-required-and-optional-is-removed-in-protocol-buffers-3
  • 路过的老哥,帮点个赞。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-12-13 20:29 | 显示全部楼层
同语言还是kyro吧,性能不差protobuf
发表于 2021-12-13 20:34 | 显示全部楼层
需要看使用场景,没有最好的,只有最适合的
发表于 2021-12-13 20:37 | 显示全部楼层
Schema和protobuff啥关系
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-5-15 04:22 , Processed in 0.141232 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表