结束了http的章节,下面我们一起来看看微服务离不开的grpc是怎么实现负载均衡、接口认证、trace追踪、失败重试、健康检查、映射服务等等,让我们一起成为面试有资可谈

1、什么是RPC

RPC 代指远程过程调用(Remote Procedure Call),它的调用包含了传输协议和编码(对象序列号)协议等等。允许运行于一台计算机的程序调用另一台计算机的子程序,而开发人员无需额外地为这个交互作用编程

2、Protobuf

Protocol Buffers 是一种与语言、平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等。相较于 JSON、XML,它更小、更快、更简单

1、语法

syntax ="proto3";
service SearchService{
    rpc Search(SearchRequest) returns (SearchResponse);
}
message SearchRequest{
string query =1;
  int32 page_number =2;
  int32 result_per_page =3;
}
message SearchResponse{
...
}
  1. 文件的第一行指定您正在使用proto3语法:如果不这样做,则协议缓冲区编译器将假定您正在使用proto2。这必须是文件的第一行非空,非注释行。
  2. 分配的字段编号用于标识消息的二进制格式,分配了最好不要修改,如果修改要及时通知使用者
  3. 范围1-15的字段编号需要一个字节来编码,包括字段编码和字段类型,16-2047的字段编号需要占用两个字节
  4. 最小是1 最大2^29 -1 ,保留字段不能使用 19000-19999

分配字段编号

  1. 单数,proto3的默认规则
  2. repeated 可以重复任意次

注释

支持单行注释//

多行注释/**/

保留字段reserved

当定义好字段后, 在后续开发中发现某个字段根本没用.

例如 string userName = 2; 字段, 这个时候最好不要进行注释或删除.

有可能以后加载相同的旧版本, 这可能会导致数据损坏, 隐私错误等. 确保不会发生这种情况的一种方法是指定要删除的字段为保留字段.

message SubscribeReq {
  
  reserved 2;
  
  int32 subReqID = 1;
  string userName = 2;
  string productName = 3;
  string address = 4;
}

或者
message Foo {
  reserved 2, 15, 9 to 11;
  reserved "foo", "bar";
}

顾名思义, 就是此字段会被保留可能在以后会使用此字段. 使用关键字 reserved 表示要保留字段编号为 2.

基本类型对照表

.proto Type

Notes

C++ Type

Java/Kotlin Type[1]

Python Type[3]

Go Type

Ruby Type

C# Type

PHP Type

Dart Type

double

double

double

float

float64

Float

double

float

double

float

float

float

float

float32

Float

float

float

double

int32

int32

int

int

int32

Fixnum or Bignum (as required)

int

integer

int

int64

int64

long

int/long[4]

int64

Bignum

long

integer/string[6]

Int64

uint32

uint32

int[2]

int/long[4]

uint32

Fixnum or Bignum (as required)

uint

integer

int

uint64

uint64

long[2]

int/long[4]

uint64

Bignum

ulong

integer/string[6]

Int64

sint32

int32

int

int

int32

Fixnum or Bignum (as required)

int

integer

int

sint64

int64

long

int/long[4]

int64

Bignum

long

integer/string[6]

Int64

fixed32

int[2]

int/long[4]

uint32

Fixnum or Bignum (as required)

uint

integer

int

fixed64

uint64

long[2]

int/long[4]

uint64

Bignum

ulong

integer/string[6]

Int64

sfixed32

int32

int

int

int32

Fixnum or Bignum (as required)

int

integer

int

sfixed64

int64

long

int/long[4]

int64

Bignum

long

integer/string[6]

Int64

bool

bool

boolean

bool

bool

TrueClass/FalseClass

bool

boolean

bool

string

String

str/unicode[5]

string

String (UTF-8)

string

string

String

bytes

string

ByteString

str

[]byte

String (ASCII-8BIT)

ByteString

string

List

自定义类型

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}

Result 为自定义的类型

嵌套类型

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result results = 1;
}

在其他地方调用

message SomeOtherMessage {
  SearchResponse.Result result = 1;
}

深度嵌套

message Outer {                  // Level 0
  message MiddleAA {  // Level 1
    message Inner {   // Level 2
      int64 ival = 1;
      bool  booly = 2;
    }
  }
  message MiddleBB {  // Level 1
    message Inner {   // Level 2
      int32 ival = 1;
      bool  booly = 2;
    }
  }
}

Any类型

Any消息类型,可以使用邮件作为嵌入式类型,而不必自己.proto定义。一个Any含有任意的序列化消息bytes,以充当一个全局唯一标识符和解析为消息的类型的URL一起。要使用该Any类型,您需要导入 google/protobuf/any.proto

import "google/protobuf/any.proto";

message ErrorStatus {
  string message = 1;
  repeated google.protobuf.Any details = 2; //只能使用repeated
}

给定消息类型的默认类型URL是type.googleapis.com/_packagename_._messagename_

引入的时候回报错

解决方法:

直接在当前目录建立层次目录 引入文件内容

grpc 调用js_数据

生成pb.go文件

enum类型

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4;
}

Corpus枚举的第一个常量映射为零:每个枚举定义必须包含一个映射为零的常量作为其第一个元素。这是因为:

  • 必须有一个零值,以便我们可以使用0作为数字默认值
  • 零值必须是第一个元素,以便与proto2语义兼容,其中第一个枚举值始终是默认值。
  • 枚举器常量必须在32位整数范围内。由于enum值在电线上使用varint编码,因此负值效率不高,因此不建议使用

map类型

message OneOf {
  uint64 Id = 1 ;
  string Title = 2;
  string Content = 3;
}
message Maps {
  map<string,string> dir = 1;
  map<int64,int32> dir2 = 2;
  map<int64,OneOf> dir3 = 3;

}

相较 Protobuf,为什么不使用 XML?

  • 更简单
  • 数据描述文件只需原来的 1/10 至 1/3
  • 解析速度是原来的 20 倍至 100 倍
  • 减少了二义性
  • 生成了更易使用的数据访问类

3、定义服务

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}