Go-gRPC入门到实战——系列一:RPC,Protobuf,gRPC入门及相关介绍

前言

RPC 代指远程过程调用(Remote Procedure Call),是分布式系统中不同节点间流行的通信方式,RPC 它的调用包含了传输协议和编码(对象序列号)协议等等。允许运行于一台计算机的程序调用另一台计算机的子程序,而开发人员无需额外地为这个交互作用编程

实际场景:

有两台服务器,分别是 A、B。在 A 上的应用 C 想要调用 B 服务器上的应用 D,它们可以直接本地调用吗?

答案是不能的,但走 RPC 的话,十分方便。因此常有人称使用 RPC,就跟本地调用一个函数一样简单

RPC 框架

我认为,一个完整的 RPC 框架,应包含负载均衡、服务注册和发现、服务治理等功能,并具有可拓展性便于流量监控系统等接入

那么它才算完整的,当然了。有些较单一的 RPC 框架,通过组合多组件也能达到这个标准

为什么要 RPC

简单、通用、安全、效率

RPC 可以基于 HTTP 吗

RPC 是代指远程过程调用,是可以基于 HTTP 协议的

肯定会有人说效率优势,我可以告诉你,那是基于 HTTP/1.1 来讲的,HTTP/2 优化了许多问题(当然也存在新的问题),所以你看到了本文的主题 gRPC

gRPC 是一个 基于 HTTP/2 协议设计的 RPC 框架,它采用了 Protobuf 作为 IDL。

在互联网时代,RPC已经和IPC一样成为一个不可或缺的基础构件。因此Go语言的标准库也提供了一个简单的RPC实现,我们将以此为入口学习RPC的各种用法。

RPC入门

1.1 RPC版”Hello, World”

Go语言的RPC包的路径为net/rpc,也就是放在了net包目录下面。因此我们可以猜测该RPC包是建立在net包基础之上的。
我们先构造一个HelloService类型,其中的Hello方法用于实现打印功能:

新建server.go文件

type HelloService struct {
     }

func (p *HelloService) Hello(request string, reply *string) error {
     
    *reply = "hello:" + request
    return nil
}

其中Hello方法必须满足Go语言的RPC规则:方法只能有两个可序列化的参数,其中第二个参数是指针类型,并且返回一个error类型,同时必须是公开的方法。

然后就可以将HelloService类型的对象注册为一个RPC服务:

func main() {
     
    rpc.RegisterName("HelloService", new(HelloService))
    listener, err := net.Listen("tcp", ":1234")
    if err != nil {
     
        log.Fatal("ListenTCP error:", err)
    }
    conn, err := listener.Accept()
    if err != nil {
     
        log.Fatal("Accept error:", err)
    }
    rpc.ServeConn(conn)
}

其中rpc.Register函数调用会将对象类型中所有满足RPC规则的对象方法注册为RPC函数,所有注册的方法会放在“HelloService”服务空间之下。然后我们建立一个唯一的TCP链接,并且通过rpc.ServeConn函数在该TCP链接上为对方提供RPC服务。

下面是客户端请求HelloService服务的代码:

新建client.go文件

func main() {
     
    client, err := rpc.Dial("tcp", "localhost:1234")
    if err != nil {
     
        log.Fatal("dialing:", err)
    }
    var reply string
    err = client.Call("HelloService.Hello", "hello", &reply)
    if err != nil {
     
        log.Fatal(err)
    }
    fmt.Println(reply)
}

首选是通过rpc.Dial拨号RPC服务,然后通过client.Call调用具体的RPC方法。在调用client.Call时,第一个参数是用点号链接的RPC服务名字和方法名字,第二和第三个参数分别我们定义RPC方法的两个参数。

运行:
分别运行:go run server.go go run client.go
输出:hello:hello

由这个例子可以看出RPC的使用其实非常简单!

1.2 Protobuf

介绍

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

语法

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 语法。同时我建议用 v2 还是 v3,都应当声明其使用的版本

2、定义 SearchService RPC 服务,其包含 RPC 方法 Search,入参为 SearchRequest 消息,出参为 SearchResponse 消息

3、定义 SearchRequest、SearchResponse 消息,前者定义了三个字段,每一个字段包含三个属性:类型、字段名称、字段编号

4、Protobuf 编译器会根据选择的语言不同,生成相应语言的 Service Interface Code 和 Stubs

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

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

1.3 gRPC

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计

多语言

C++
C#
Dart
Go
Java
Node.js
Objective-C
PHP
Python
Ruby

特点

1、HTTP/2

2、Protobuf

3、客户端、服务端基于同一份 IDL

4、移动网络的良好支持

5、支持多语言

概览

Go-gRPC入门到实战——系列一:RPC,Protobuf,gRPC入门及相关介绍_第1张图片

讲解

1、客户端(gRPC Sub)调用 A 方法,发起 RPC 调用

2、对请求信息使用 Protobuf 进行对象序列化压缩(IDL)

3、服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回

4、对响应结果使用 Protobuf 进行对象序列化压缩(IDL)

5、客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果

参考文章:https://eddycjy.com/posts/go/grpc/2018-09-22-install/

你可能感兴趣的:(gRPC,grpc,rpc)