• rpc通信的实现方式(以grpc为例)


    基础知识

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其他可实现功能

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

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

  • 相关阅读:
    Unity UI自适应
    成为一个优秀的测试工程师需要具备哪些知识和经验?
    在pytorch中对于张量维度的理解
    Guava限流器原理浅析
    《Python进阶系列》二十七:字符串类型代码的执行函数——eval()、exec()和compile()
    【leetcode速通java版】02——有序数组、子数组、螺旋矩阵
    uboot学习预备知识
    操作系统读者-写者问题中算是允许多个进程进入临界区吗
    springboot和springcloud版本对应
    VCAP-DCV VMware vSphere: 运维、扩展和安全防护 [V8.0]
  • 原文地址:https://blog.csdn.net/corruptwww/article/details/127768046