入门
RPC简介
RPC(Remote Procedure Call Protocol),远程调用协议。调用远程的函数实现功能。
广泛应用于分布式,微服务,解耦,跨语言通信等。RPC的目标就是把远程调用的过程透明化。
RPC把函数调用参数和返回值进行序列化,然后通过网络服务发送和接收。
gRPC简介
gRPC是google的开源的高可用的通用的RPC框架
gRPC使用protobuf作为接口定义语言和基础消息交换格式
gRPC服务方法
1.一元RPC(简单RPC)
客户端发送一个单独的请求,并且接收服务端对这个请求的单独回复,类似普通的函数调用
rpc SayHello(HelloRequest) returns (HelloResponse);
2.服务端流RPC
客户端发送一个单独的请求,服务端返回流式数据,客户端读取流式数据直到EOF,gRPC保证每个调用中的信息排序
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
3.客户端流RPC
客户端写入流式数据,写入完成后等待服务端读取并返回单独的结果,gRPC保证每个调用中的信息排序
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
4.双向流RPC
双方都使用读写流发送一系列消息。 这两个流是独立运行的,因此客户端和服务器可以按照自己需要的顺序进行读写,例如,服务器可以在写响应之前等待接收所有客户端消息,或者可以先读取一条消息再写入一条消息,或其他一些读写组合。 gRPC保证每个调用中的信息排序
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
protobuf简介
google开源的成熟的语言无关,平台无关的可扩展的结构化数据序列化机制,类似xml,但是更小更快更简单。
可以通过一次定义数据结构,通过生成的源代码轻松编写和读取各种数据流以及使用多种语言的结构化数据。
protobuf需要在原型文件定义数据结构,其原型文件的扩展名是.proto
。
安装
protobuf
MacOS
brew的安装参考:https://brew.sh/
brew的安装命令:/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
使用brew安装protobuf:brew install protobuf
验证安装:
$ protoc --version
libprotoc 3.14.0
grpc-go
这里的话,先建立一个go mod项目,在项目下进行操作,项目名myproto:
然后在项目目录里运行go get -u google.golang.org/grpc
来安装grpc-go
这一步是在go安装grpc库,也就是让go支持grpc
$ go get -u google.golang.org/grpc
go: google.golang.org/grpc upgrade => v1.35.0
go: google.golang.org/protobuf upgrade => v1.25.0
go: github.com/golang/protobuf upgrade => v1.4.3
go: golang.org/x/text upgrade => v0.3.5
go: golang.org/x/sys upgrade => v0.0.0-20210124154548-22da62e12c0c
go: golang.org/x/net upgrade => v0.0.0-20210119194325-5f4716e94777
go: google.golang.org/genproto upgrade => v0.0.0-20210203152818-3206188e46ba
go: downloading golang.org/x/net v0.0.0-20210119194325-5f4716e94777
go: downloading google.golang.org/genproto v0.0.0-20210203152818-3206188e46ba
go: downloading golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c
go: downloading golang.org/x/text v0.3.5
golang protobuf
这一步是安装protoc-gen-go,来让protoc支持生成go代码
在项目目录下运行go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
$ go get -u github.com/golang/protobuf/{
proto,protoc-gen-go}
go: found github.com/golang/protobuf/protoc-gen-go in github.com/golang/protobuf v1.4.3
go: found github.com/golang/protobuf/proto in github.com/golang/protobuf v1.4.3
go: google.golang.org/protobuf upgrade => v1.25.0
这个时候检查一下项目的go.mod文件,应该是这样的:
至此环境配置完成。
实战
一元RPC
这里我们用两个数加和函数功能做例子。
编写proto文件,定义接口
在项目根目录新建目录及文件UnaryRPC/proto/unary.proto
文件内容:
//指定使用proto3(proto2,3有很多不同,不可混写)
syntax = "proto3";
//指定生成的go_package,简单来说就是生成的go代码使用什么包,因为我们想用proto这个文件夹来装这个代码,所以package proto
option go_package = ".;proto";
//定义rpc服务
//此处rpc服务的定义,一定要从服务端的角度考虑,即接受请求,处理请求并返回响应的一端
//请求接受一个SumReq(num1, num2)
//响应回发一条sum = num1 + num2
service Sum{
rpc Sum(SumReq)returns(SumRes){}
}
message SumReq {
int32 num1 = 1;
int32 num2 = 2;
}
message SumRes {
int32 sum = 1;
}
生成go rpc代码
进入命令行,切到unary.proto文件所在的目录,执行:protoc --go_out=plugins=grpc:. unary.proto
这条命令含义是在当前目录编译unary.proto,插件使用grpc
执行完毕可以在同目录看到一个unary.pb.go
来看一下生成文件的内容,重点关注:
我们在应用这个proto的时候:
- 客户端调用SumClient接口的Sum方法,传入SumReq,接收SumRes
- 服务端实现SumServer接口的Sum方法,接收SumReq,返回SumRes
编写服务端
文件:UnaryRPC/server/server.go
内容,有疑问看注释,再有疑问留评论:
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"log"
"net"
// import UnaryRPC 生成的proto
"myproto/UnaryRPC/proto"
)
// 实现SumServer接口
type SumServer struct{
}
func (*SumServer) Sum(ctx context.Context, req *proto.SumReq) (*proto.SumRes, error) {
// 暂时不对ctx进行处理
return &proto.SumRes{
Sum: req.Num1 + req.Num2}, nil
}
func main() {
// 定义rpc server监听的端口
lis, err := net.Listen("tcp", ":6012")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// 实例化一个新的服务端对象
s := grpc.NewServer()
// 向服务端对象注册SumServer服务
proto.RegisterSumServer(s, &SumServer{
})
// 注册服务端反射服务
reflection.Register(s)
// 启动服务
s.Serve(lis)
// 可配合ctx实现服务端的动态终止
//s.Stop()
}
编写客户端
文件:UnaryRPC/client/client.go
内容,依旧是看注释:
package main
import (
"context"
"google.golang.org/grpc"
"log"
"myproto/UnaryRPC/proto"
"time"
)
func main() {
// 向服务端建立连接
grpcConn, err := grpc.Dial("127.0.0.1"+":6012", grpc.WithInsecure())
if err != nil {
log.Fatalln(err)
}
// 实例化一个SumClient对象
client := proto.NewSumClient(grpcConn)
// 设置超时
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// 调用Sum函数
res, err := client.Sum(ctx, &proto.SumReq{
Num1: 54,
Num2: 35,
})
if err != nil {
log.Fatalln(err)
}
// 输出结果
log.Println("the sum is", res.Sum)
}
运行展示
目前的目录结构
- 服务端