nodejs微服务:关于Protobuf的使用

Protobuf是Google开发的轻量级数据序列化协议,用于结构化数据存储和RPC接口定义。它比JSON和XML更小、更快,支持多语言和跨平台,但可读性较差且应用范围相对较窄。Protobuf的基本语法涉及消息定义、服务定义以及enum和repeated关键字。它可以定义嵌套消息,提供默认值,并且可以用于定义RPC服务接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Protobuf

  • Protobuf是Protocol Buffers的简称,它是Google公司开发的一种数据描述语言
  • 是一种轻便高效的结构化数据存储格式,可以用于结构化数据,或者说序列化
  • 它很适合做数据存储或 RPC 数据交换格式
  • 可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式
  • 它是一种灵活,高效,自动化的机制,用于序列化结构化数据,对比于 XML和JSON,他更小,更快、更简单
  • 总之它是微服务中需要使用的东西,Protobuf刚开源时的定位类似于XML、JSON等数据描述语言
  • 通过附带工具生成代码并实现将结构化数据序列化的功能
  • 这里我们更关注的是Protobuf作为接口规范的描述语言,可以作为设计安全的跨语言RPC接口的基础工具
  • 总结
    • protobuf是类似与json一样的数据描述语言(数据格式)
    • protobuf非常适合于RPC数据交换格式

1 ) 优点

  • 序列化后体积相比Json和XML很小,适合网络传输
  • 支持跨平台多语言
  • 消息格式升级和兼容性很好
  • 序列化反序列化速度很快,快于Json的处理速度

2 ) 缺点

  • 应用不够广(相比xml和json)
  • 二进制格式导致可读性差
  • 缺乏自描述

Protobuf 基本语法

1 ) 文档

2 ) 示例

syntax = "proto3"; // 版本

package greeter; // 包名 nodejs中理解为命名空间

// 对外暴露的服务
service Greeter { 
   rpc sayHello (HelloRequest) returns (HelloReply) {} // 对外暴露的函数名,参数和返回值
}

// 请求参数对象
message HelloRequest {  
  // 名字
  string name = 1;
  // 年龄
  int32 age = 2 ;
  // 爱好
  repeated string hobby = 3; // string类型的数组 
}

// 返回参数对象
message HelloReply {
  string message = 1;
  repeated string hobby = 2;
}

3 ) 说明

  • protobuf消息的定义(或者称为描述)通常都写在一个以 .proto 结尾的文件中
  • 该文件的第一行指定正在使用 proto3 语法:如果不这样做,协议缓冲区编译器将假定正在使用proto2
  • 这也必须是文件的第一个非空的非注释行
  • 第二行 package 命名空间包名称
  • 最后message关键字定义一个HelloRequest的消息体,类似于Nodejs语言中的对象,是包含一系列类型数据的集合
  • 许多标准的简单数据类型都可以作为字段类型,包括 bool,int,float,double,和 string
  • 也可以使用其他 message 类型作为字段类型
  • 在message中有一个字符串类型的value成员,该成员编码时用1代替名字
  • 我们知道,在json中是通过成员的名字来绑定对应的数据,但是Protobuf编码却是通过成员的唯一编号来绑定对应的数据
  • 因此Protobuf编码后数据的体积会比较小,能够快速传输,缺点是不利于阅读

4 ) message的格式说明

  • 消息由至少一个字段组合而成,类似于Nodejs中的Json对象,每个字段都有一定的格式
    • // 注释格式 注释尽量也写在内容上方
    • (字段修饰符)数据类型 字段名称 = 唯一的编号标签值
  • 唯一的编号标签:代表每个字段的一个唯一的编号标签,在同一个消息里不可以重复
    • 这些编号标签用与在消息二进制格式中标识你的字段,并且消息一旦定义就不能更改
    • 需要说明的是标签在1到15范围的采用一个字节进行编码,所以通常将标签1到15用于频繁发生的消息字段
    • 编号标签大小的范围是1到2的29次,其中 19000-19999是官方预留的值,不能使用
  • 注释格式:向.proto文件添加注释
    • 可以使用C/C++/java/Go风格的双斜杠(//) 语法格式
    • 或者 /* … */

5 ) proto类型对比

  • 由于js是一种弱类型语言,所以这里没有详细的类型展示,可以把proto中的类型和typescript中的类型对应
  • 其中proto中的数字类型对应ts的 number 类型
  • proto的字符串类型对应ts的 string 类型
  • proto的 boolean 对应ts的 boolean 类型

Protobuf 高级语法

1 ) message嵌套

  • messsage除了能放简单数据类型外,还能存放另外的message类型,如下:
    syntax = "proto3"; // 指定版本信息,不指定会报错 
    package helloworld; // 包名 nodejs中理解为命名空间 
    //message为关键字,作用为定义一种消息类型 
    message Person {
      // 名字
      string name = 1;
      // 年龄
      int32 age = 2;
      // 定义一个message
      message PhoneNumber {
        string number = 1;
        int64 type = 2;
      }
      PhoneNumber phone = 3;
    }
    

2 ) repeated关键字

  • repeated关键字类似与js中的数组,编译之后对应的也是js的数组,用法如下:
    syntax = "proto3"; //指定版本信息,不指定会报错
    package helloworld; 
    // message为关键字,作用为定义一种消息类型
    message Person {
      // 名字
      string name = 1;
      // 年龄
      int32 age = 2;
      // 定义一个message
      message PhoneNumber {
        string number = 1;
        int64 type = 2;
      }
      repeated PhoneNumber phone = 3;
    }
    

3 ) 默认值

  • 解析数据时,如果编码的消息不包含特定的单数元素,则解析对象对象中的相应字段将设置为该字段的默认值
  • 不同类型的默认值不同,具体如下:
    • 对于字符串,默认值为空字符串
    • 对于字节,默认值为空字节
    • 对于bools,默认值为false
    • 对于数字类型,默认值为零
    • 对于枚举,默认值是第一个定义的枚举值,该值必须为0
    • repeated字段默认值是空列表
    • message字段的默认值为空对象

4 ) enum关键字

  • 在定义消息类型时,可能会希望其中一个字段有一个预定义的值列表
  • 比如说,电话号码字段有个类型,这个类型可以是,home,work,mobile
  • 我们可以通过enum在消息定义中添加每个可能值的常量来非常简单的执行此操作
  • 实例如下:
    syntax = "proto3"; //指定版本信息,不指定会报错
    
    package pb; //后期生成go文件的包名
    
    // message为关键字,作用为定义一种消息类型
    message Person {
    	// 名字
    	string name = 1;
    	// 年龄
    	int32 age = 2 ;
    	// 定义一个message
    	message PhoneNumber {
    		string number = 1;
    		PhoneType type = 2;
    	}
        repeated PhoneNumber phone = 3;
    }
    
    // enum为关键字,作用为定义一种枚举类型
    enum PhoneType {
    	MOBILE = 0;
    	HOME = 1;
    	WORK = 2;
    }
    
    • 如上,enum的第一个常量映射为0
    • 每个枚举定义必须包含一个映射到零的常量作为其第一个元素
    • 这是因为:必须有一个零值,以便我们可以使用0作为数字默认值
    • 零值必须是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值

5 ) 定义RPC服务

  • 如果需要将message与RPC一起使用,则可以在 .proto 文件中定义RPC服务接口

  • protobuf编译器将根据你选择的语言生成RPC接口代码,官方示例如下:

    syntax = "proto3";
    
    package greeter;
    
    // The greeting service definition.
    service Greeter {
      // Sends a greeting
      rpc SayHello (HelloRequest) returns (HelloReply) {}
    }
    
    // The request message containing the user's name.
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings
    message HelloReply {
      string message = 1;
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值