分布式项目-RPC|青训营笔记

93 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的的第3天

Protobuf 实现RPC调用

一、ProtoBuf

protobuf是类似于Json的一种用于数据序列化和反序列化的程序,下面介绍Protobuf的使用步骤。

  1. 定义proto文件, 文件的内容就是存储或者是发送的数据结构或者是传输协议
  2. 使用protobuf编译器便🧬编译自定义的.proto文件,生成.pb.{cc, h}
  3. 使用protobuf的API进行消息的读写

定义proto文件

  • 为需要序列化的数据结构添加消息message
  • 为消息中每一个字段指定:name, type, tag

编译文件

生成xxx.pb.{h, cc}两个文件,其中内涵了比如说 设定变量的值,进行序列化,反序列化的api

使用API进行序列化 & 反序列化

在新的文件中包含生成的头文件进行调用

二、RPC

什么是RPC

RPC是远程过程调用 (Remote Proceduce Call) ,目标主要是让分布式计算更加容易。RPC框架提供了一种透明的机制让使用者 不用区分本地调用和远程调用

数据远端调用过程

Screen Shot 2022-07-29 at 8.49.01 PM.png

图片来源

这里假设用Json进行序列化操作,假设client端调用了服务端的函数,其实就是向服务端发送了函数f(x)的数据(包括传入的参数,获得的返回值类型等),然后经过序列化 之后经过网络发送到对端。对端反序列化获得结构化的数据,进行函数调用,然后以相同的方式发送回client端

如何做到序列化呢?

使用google的protobuf,前面有描述

使用gRPC框架

适用场景:

  • 分布式场景,低延迟高吞吐量
  • 点对点实时通信
  • 网络受限的环境,适用protobuf进行序列化消息

参考实现

单项RPC使用(远程的函数调用)

proto文件

syntax = "proto3";
package  Helloworld;
​
​
//rpc 接口
service Greetes {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}
​
message HelloReply {
  string name = 1;
  string message = 2;
}
​
message HelloRequest {
  string name = 1;
  string message = 2;
}

我们的服务名就是Greetes, 其中SayHello就是实现的函数,参数返回值就是下面定义的结构

server

package main
​
import (
  "context"
  "fmt"
  "net"
)
​
type Server struct {
}
​
//proto生成pb文件,
func (s *Server) SayHello(con context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
  return &pb.HelloReply{Name: "呱呱", Message: "早上好"}, nil
}
​
func main() {
  lis, err := net.Listen("tcp", ":9981")
  if err != nil {
    fmt.Println(err)
    return
  }
  //定义一个rpc的server
    server := grpc.NewServer()
   //注册服务,相当与注册SayHello接口
    pb.RegisterGreetsServer(server, &Server{})
    //进行映射绑定
    reflection.Register(server)
​
    //启动服务
    err = server.Serve(lis)
    if err != nil {
        fmt.Println(err)
        return
    }
  
}
​

Client

 1func main() {
 2    //创建一个grpc连接
 3    conn, err := grpc.Dial("localhost:8002", grpc.WithInsecure())
 4    if err != nil {
 5        fmt.Println(err)
 6        return
 7    }
 8    defer conn.Close()
 9
10    //创建RPC客户端
11    client := pb.NewGreetsClient(conn)
12    //设置超时时间
13    _, cancel := context.WithTimeout(context.Background(), time.Second)
14    defer cancel()
15
16    // 调用方法
17    reply, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "小冰", Message: "你好吗"})
18    if err != nil {
19        log.Fatalf("couldn not greet: %v", err)
20    }
21    log.Println(reply.Name, reply.Message)
22}

Client端调用方法SayHello就是进行了远程的调用Server的函数