gRPC原理详解
Posted Golang JAVA进阶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gRPC原理详解相关的知识,希望对你有一定的参考价值。
概述
为什么使用 gRPC?
有了 gRPC, 我们可以一次性的在一个 .proto 文件中定义服务并使用任何支持它的语言去实现客户端和服务器,反过来,它们可以在各种环境中,从Google的服务器到你自己的平板电脑—— gRPC 帮你解决了不同语言及环境间通信的复杂性。使用 protocol buffers 还能获得其他好处,包括高效的序列号,简单的 IDL 以及容易进行接口更新。
相比其他开源的RPC框架,gRPC有如下几个特点
(1)支持多种语言。
(2)基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口及客户端Stub。
(3)通信协议基于标准的HTTP/2设计,支持双向流、消息头压缩、单TCP的多路复用、服务端推送等特性。
(4)序列化支持Protocol buffer和JSON,Protocol buffer是一种语言无关的高性能序列化框架,基于“HTTP/2+Protocol buffer”,保障了RPC调用的高性能。
调用模型
1、客户端(gRPC Stub)调用 A 方法,发起 RPC 调用。
2、对请求信息使用 Protobuf 进行对象序列化压缩(IDL)。
3、服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回。
4、对响应结果使用 Protobuf 进行对象序列化压缩(IDL)。
5、客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果。
调用方式
gRPC 允许你定义四类服务方法:
单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。
rpc SayHello(HelloRequest) returns (HelloResponse){
服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}
客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}
双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}
一、Unary RPC:一元 RPC
Chat.proto
syntax = "proto3";
The Go package name is "timestamppb".
option go_package = "google.golang.org/protobuf/types/known/timestamppb";
package chat;
message Message {
string name = 1;
int32 age = 2;
}
message ResponseMessage {
int32 status = 1;
string body = 2;
}
service ChatService {
rpc SayHello (Message) returns (Message){};
}
//通过命令行生成对应的代码
protoc --go_out=plugins=grpc:chat chat.proto
Chat.go
type Server struct {
Body string
}
func (s *Server) SayHello(ctx context.Context, message *Message) (*Message, error) {
log.Printf("Received message form client: %s", message.Name)
//return &Message{Body: "Hello From The Server!"}, nil
return &Message{Name: "Wendy", Age: 30}, nil
}
Server.go
func main() {
fmt.Println("Go gRPC Beginners Tutorial!")
lis, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatalf("Failed to listen on port 9090: %v", err)
}
s := chat.Server{}
grpcServer := grpc.NewServer()
chat.RegisterChatServiceServer(grpcServer, &s)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve GRPC: %v", err)
}
}
创建 gRPC Server 对象,你可以理解为它是 Server 端的抽象对象。
将 ChatService(其包含需要被调用的服务端接口)注册到 gRPC Server。的内部注册中心。这样可以在接受到请求时,通过内部的 “服务发现”,发现该服务端接口并转接进行逻辑处理。
创建 Listen,监听 TCP 端口。
gRPC Server 开始 lis.Accept,直到 Stop 或 GracefulStop。
Client.go
func main() {
var conn *grpc.ClientConn
conn, err := grpc.Dial(":9000", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %s", err)
}
defer conn.Close()
c := chat.NewChatServiceClient(conn)
response, err := c.SayHello(context.Background(), &chat.Message{Name: "Hello From Client!", Age: 20})
if err != nil {
log.Fatalf("Error when calling SayHello: %s", err)
}
log.Printf("Response from server: %+v", response)
}
总结
预留
预留
以上是关于gRPC原理详解的主要内容,如果未能解决你的问题,请参考以下文章