gRPC简介
source link: https://blog.p2hp.com/archives/11189
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
gRPC(Remote Procedure Calls)
GRPC是一个高性能、通用的开源RPC框架,基于底层HTTP/2协议标准
和协议层Protobuf序列化协议
开发,支持众多的开发语言。
gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
gRPC使用protocol buffers
作为接口描述语言(IDL)以及底层的信息交换格式
- 基于 HTTP/2 之上的二进制协议(Protobuf 序列化机制);
- 一个连接上可以多路复用,并发处理多个请求和响应;
- 多种语言的类库实现;
- 服务定义文件和自动代码生成(.proto 文件和 Protobuf 编译工具)。
- RPC 还提供了很多扩展点,用于对框架进行功能定制和扩展,例如,通过开放负载均衡接口可以无缝的与第三方组件进行集成对接(Zookeeper、域名解析服务、SLB 服务等)
https://www.colabug.com/4616436.html
Simple RPC
简单rpc ,这就是一般的rpc调用,一个请求对象对应一个返回对象
proto语法:
rpc simpleHello(Person) returns (Result) {}
Server-side streaming RPC
服务端流式rpc,一个请求对象,服务端可以传回多个结果对象
proto语法:
rpc serverStreamHello(Person) returns (stream Result) {}
Client-side streaming RPC
客户端流式rpc 客户端传入多个请求对象,服务端返回一个响应结果
proto语法:
rpc clientStreamHello(stream Person) returns (Result) {}
Bidirectional streaming RPC
双向流式rpc,结合客户端流式rpc和服务端流式rpc,可以传入多个对象,返回多个响应对象
proto语法:
rpc biStreamHello(stream Person) returns (stream Result) {}
golang
版本的grpc
要求go
版本要在1.6
以上
install gRPC
使用go get
命令安装grpc
包
$ go get -u google.golang.org/grpc
由于某些不可逆原因,上面命令会报连接超时,可以到
github
上将项目clone
到$GOPATH/src/google.golang.org/
下
$ cd $GOPATH/src/google.golang.org
$ git clone [email protected]:grpc/grpc-go.git grpc
install Protocol Buffers v3
$ apt install protobuf-compiler
install protoc plugin
安装golang
版本对应的protobuf
生成工具
$ go get -u github.com/golang/protobuf/protoc-gen-go
运行demo
进入example
目录
$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld
删除原来的helloworld.pb.go
文件,并使用protoc
生成自己生成一个
$ rm helloworld/helloworld.pb.go // 删除原来的helloworld.pb.go文件
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld // 根据 .proto 文件生成对应的.go文件
编写grpc
接口时,在.proto
文件定义接口通信数据格式和接口信息,然后通过protoc
自动生成对应的go
代码,大大方便了开发
-I PATH
:specify the directory in which to search for imports. May be specified multiple times; directories will be searched in order. If not given, the current working directory is used.--go_out
:指定输出go
代码plugins=grpc
:.proto
中的service
是grpc
扩展的功能,需要使用grpc
插件进行解析才能生成对应的接口定义代码。
运行 grpc server
和 grpc client
$ go run greeter_server/main.go // 启动grpc server
$ go run greeter_client/main.go // 启动grpc client
如果helloworld下面没有greeter_server和greeter_client文件夹执行下列两种其中一种命令
$ go get -u google.golang.org/grpc/examples/helloworld/greeter_client
$ go get -u google.golang.org/grpc/examples/helloworld/greeter_server
$ go get -u google.golang.org/grpc
开发一个求和的grpc
接口
定义.proto文件
在proto
目录下创建接口描述文件sum.proto
文件:
Message命名采用驼峰命名方式,字段命名采用小写字母加下划线分隔方式
Enums类型名采用驼峰命名方式,字段命名采用大写字母加下划线分隔方式
即便业务上不需要参数也必须指定一个请求消息,一般会定义一个空message。
syntax = "proto3"; // 使用 proto3,没写默认proto2。建议grpc配合proto3使用,兼容性更高
// java生成选项
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
package proto; // 生成的go所属的package
// 需要序列化的结构体
message SumResp {
int64 sum = 1;
}
message SumReq {
int64 a = 1;
int64 b = 2;
}
service CalcSvc {
// 每个rpc接口声明都必须有且一个参数和一个返回值
rpc Sum(SumReq) returns (SumResp) {}
}
根据接口描述文件生成源码
进入proto
目录,执行
$ protoc sum.proto --go_out=plugins=grpc:.
可以看到,在本目录下生成sum.pb.go
文件,且package
为proto
开发服务端接口
首先查看生成的sum.pb.go
文件,可以看到根据sum.proto
文件中的CalcSvc
接口定义生成了对应的接口:
// CalcSvcServer is the server API for CalcSvc service.
type CalcSvcServer interface {
// 每个rpc接口声明都必须有且一个参数和一个返回值
Sum(context.Context, *SumReq) (*SumResp, error)
}
开发服务端接口只要就是根据这些接口定义实现具体的业务逻辑
在项目下创建service/main.go
:
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"grpc-demo/proto" //路径可能不同,看自己的proto包放在哪个目录下
"log"
"net"
)
// 类型断言
var _ proto.CalcSvcServer = new(CalcSvc)
type CalcSvc struct{}
func (CalcSvc) Sum(ctx context.Context, req *proto.SumReq) (resp *proto.SumResp, err error) {
// 建议使用GetA,不要直接使用req.A,可能存在req=nil的情况
a := req.GetA()
b := req.GetB()
log.Println("request coming ...")
return &proto.SumResp{
Sum: a + b,
}, err
}
func main() {
lis, err := net.Listen("tcp", ":8888")
if err != nil {
log.Fatal(err)
}
// 注册服务到gRPC
s := grpc.NewServer()
proto.RegisterCalcSvcServer(s, &CalcSvc{})
// 启用Server Reflection,可以使用gRPC CLI去检查services
// https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md
reflection.Register(s)
// 启动服务
if err := s.Serve(lis); err != nil {
log.Fatal(err)
}
}
客户端访问
在项目下创建client/main.go
:
package main
import (
"context"
"google.golang.org/grpc"
"grpc-demo/proto" //路径可能不同,看自己的proto包放在哪个目录下
"log"
)
func main() {
// 创建gRPC连接
// WithInsecure option 指定不启用认证功能
conn, err := grpc.Dial(":8888", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
// 创建gRPC client
client := proto.NewCalcSvcClient(conn)
// 请求gRPC server
resp, err := client.Sum(context.Background(), &proto.SumReq{
A: 5,
B: 10,
})
if err != nil {
log.Fatal(err)
}
log.Printf("5 + 10 = %d", resp.GetSum())
}
$ go run service/main.go &
$ go run client/main.go
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK