rpc通信的实现方式(以grpc为例)以及proto的语法详解

基础知识

RPC(Remote Procedure Call):远程过程调用。它是一种调用方式,可以像调用本地方法那样调用远端方法。
protobuf(Protocol Buffers):一种开源跨平台的序列化数据结构的协议,是一种体积小、传送快的数据格式。
IDL(Interface description language):接口描述语言。

为什么要在微服务中使用RPC:
当接口调用和实现在同一个地址空间/同一块内存时,这个称为本地函数调用。
在分布式应用中,接口调用和实现分别在两个子系统内。

RPC需要解决的三个问题(工作原理):
通信问题(网络传输协议)
序列化和反序列问题(编译)
call ID 映射问题(函数映射)

服务类型:传入一个/多个请求对象,返回一个/多个返回对象

服务端server:服务提供方,提供结构体(函数)方法和参数等。
客户端client:服务调用方,调用结构体(函数)方法和参数等。

GRPC使用protobuf数据格式承接数据,使用http2传输。
GRPC优点:传输效率高(TCP/HTTP2),性能消耗低(二进制传输),服务治理方便(自带)。
gRPC 应用的开发流程:安装 protobuf 编译器 protoc、protoc-Go 插件;编写.proto文件、生成.go文件;编写服务器端与客户端代码。

GRPC应用的开发流程

安装插件;编写.proto文件、生成.go文件;编写服务器端与客户端代码。

0、安装 protobuf 编译器 protoc、protoc-Go 插件,获取后缀为.proto的protobuf文件的使用例demo。
1、在.proto文件中定义自己的结构体和参数,结构体内不包含内容。
2、运行IDL生成命令生成后缀为.pb.go的文件,里面包含编码(序列化)的代码和结构体的代码。将该文件分发到服务端和客户端上。
(在新版grpc中,官方推荐将编码和结构体的代码分为两个文件,使用protoc-gen-go和protoc-gen-go-grpc插件,文件后缀为.pb.go和_grpc.pb.go,对应为包含用于 protobuf 消息的编码(序列化/反序列化)的代码,包含 gRPC 服务器和客户端的代码)
3、我们需要在服务端中构建main执行函数,实现.pb.go的文件中的结构体(即接口)并注册。

服务端main.go:监听tcp端口,创建grpc服务器,实现结构体内容,把结构体注册到服务器里,运行服务器。
客户端main.go:使用grpc自己的NewEchoClient方法,通过ip:port建立连接,运行.pb.go的文件中自定义的单例方法,获取自定义结构体实例,在实例中调用服务端的方法。

让gRPC服务支持HTTP 服务请求

思路:
1、使用runtime.NewServeMux(),新建一个Mux结构体,类似于httpMux路由
2、把下游节点注册到路由里面
3、使用ListenAndServe方法监听运行

var (
serverAddr=":8081"
grpcServerEndpoint = flag.String(  "grpc-server-endpoint",value: "localhost:50055", "gRPC server endpoint")
)
//可以理解为每个rs都需要持续跟下游建立连接
func run error{
ctx := context.Background( )
ctx, cancel := context.withCancel(ctx)
defer cancel( )
mux := runtime.NewServeMux( )
opts:=[]grpc.Dial0ption{grpc.withInsecure( )}
err := gw.RegisterEchoHandlerFromEndpoint(ctx,mux,*grpcServerEndpoint,opts)
if err != nil {
return err
}
return http.ListenAndServe(serverAddr, mux)

其他可实现功能

1、自定义codec 编码与解码规则CustomCodec
2、自定义未知方法回调UnknownServiceHandler
3、基于自定义回调可对请求服务做方法级管控

自定义编码器实现方法:构建支持原始字节、支持proto的解码器。如果拿到的是原始字节,则不需要解码,如果不是原始字节则需要通过proto转换一下。构建输出方法,设置到server参数中。
自定义回调实现方法:构建一个下游连接器。构建一个回调类。上游与下游相互拷贝数据。

proto语法

在proto文件中,我们需要做什么?
定义服务和消息。之后这些服务和消息会被插件编译成go文件,我们在服务端中实现编译后的go文件的方法,在客户端中使用编译后的go文件的方法。
举个例子就懂了:

syntax = "proto3";
// 枚举类型
enum Status {
  UNKNOWN = 0;
  ACTIVE = 1;
  INACTIVE = 2;
  SUSPENDED = 3;
  DELETED = 4;
}

message Request {
  // 定义请求消息的字段
    string name = 1;
  Status status = 2;
}

message Response {
  // 定义响应消息的字段
  // 每个字段定义一个数字是为了数据序列化
    int name = 1;
  Status status = 2;
}

service YourService {
  rpc YourMethod(Request) returns (Response);
}

需要注意的是,生成的pb.go文件中,会提供getter()和setter()两个方法去设置和调用message消息中的字段值,如request.getName()。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值