共计 3943 个字符,预计需要花费 10 分钟才能阅读完成。
前言
古代的软件服务大多数是分布式应用程序,通过裸露本人的 API 对内或对外提供了一系列的性能点。服务与服务之间有时是跨语言、跨平台通信的。
为了解决这些简单场景,市面上也涌现了有很多解决方案。比方构建 RESTful 服务,将服务能力转化为资源汇合;也有面向函数调用的客户端 - 服务器模式:近程过程调用(Remote Procedure Calls)。明天要介绍的 gRPC 就是后者的演变,一个十分受欢迎分布式过程间通信技术。
意识 gRPC
gRPC 是 Google 在 2015 年推出的 RPC 框架。在意识 gRPC 之前,咱们先来理解下 RPC 的相干常识。RPC 次要使用于分布式程序中,它构建了客户端 - 服务器模型,相似于申请 - 响应通信形式,只不过这种申请被咱们形象为了函数办法 + 入参信息,底层的网络通信则被屏蔽了起来,到最初就像本地办法调用一样。
Protocol Buffers
下面提到了函数的入参信息,有入参就有对象类型,而端到端的对象类型就势必波及到
网络通信过程中的字节序列化和反序列化过程。在 gRPC 中,采纳了 Protobuf(Protocol Buffers)作为序列化和反序列化协定。它是一种轻便高效的结构化数据存储格局,基于二进制编码构建,可能缩小 CPU 的简单解析,保障了 RPC 调用的高性能。
另外 Protobuf 反对多种编程语言,咱们只须要对其进行接口定义形容,便能够依据形容文件主动生成客户端和服务端须要应用到的构造体和办法函数,就像是代码主动生成一样,大大提高了咱们的编程效率。
HTTP/2
gRPC 是基于 HTTP/2 设计的,HTTP/2 也是 2015 年公布的,它是下一代的 HTTP 协定,具备很多高级性能,如:
- 基于二进制格局传输,传输速度更快,更紧凑,不易出错。
- 多路复用,单个连贯可发送多个申请。
- 对报头压缩,能升高传输开销。
- 容许服务器被动推送。
正是这些 HTTP/2 的个性,使得 gRPC 可能应用较少的资源,取得较快的响应,在挪动端设施上更加省电省流量。
gRPC 的应用
接口定义
当咱们开发一个 gRPC 应用程序时,要做的第一件事件就是定义一个接口形容文件。在这个文件里,咱们会将函数、参数信息都形容进去,就像上面这个 ProductInfo.proto 文件一样:
// ProductInfo.proto
syntax = "proto3";
package ecommerce;
// 服务里的接口列表
service ProductInfo {rpc addProduct(Product) returns (ProductID);
rpc getProduct(ProductID) returns (Product);
}
// 参数信息
message Product {
string id = 1;
string name = 2;
string description = 3;
}
message ProductID {string value = 1;}
gRPC 服务端
当咱们拿到定义好的接口形容文件 ProductInfo.proto 后,就能够应用 Protobuf 编译器:protoc 来生成咱们的服务端代码了。假如咱们的服务端采纳的是 Go 语言,则在通过一系列插件的装置后,咱们就能够应用上面的命令来编译生成代码了:
protoc --proto_path=IMPORT_PATH --go_out=OUT_DIR --go_opt=paths=source_relative path/to/file.proto
protoc 反对多种语言,具体大伙能够依照官网提供的来生成代码,总之,咱们将 接口定义文件,转化为了咱们须要的服务端代码,咱们只须要援用并实现接口函数即可为客户端提供对应的服务了:
import (
...
"context"
pb "github.com/grpc-up-and-running/samples/ch02/productinfo/go/proto"
"google.golang.org/grpc"
...
)
// ProductInfo 接口的实现
// Add product remote method
func (s *server) AddProduct(ctx context.Context, in *pb.Product) (*pb.ProductID, error) {// 具体的业务逻辑}
// Get product remote method
func (s *server) GetProduct(ctx context.Context, in *pb.ProductID) (*pb.Product, error) {// 具体的业务逻辑}
当然,定义完后还得注册下服务:
func main() {lis, _ := net.Listen("tcp", port)
s := grpc.NewServer()
pb.RegisterProductInfoServer(s, &server{})
if err := s.Serve(lis); err != nil {log.Fatalf("failed to serve: %v", err)
}
}
gRPC 客户端
与服务端相似,咱们将依据 ProductInfo.proto 文件生成客户端的代码,即所谓的存根(Stub)。假如咱们的客户端应用的是 Java 语言,则咱们能够像上面一样应用 Stub 了:
// 依据服务地址创立通道
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
.usePlaintext(true)
.build();
// 依据通道创立存根
ProductInfoGrpc.ProductInfoBlockingStub stub =
ProductInfoGrpc.newBlockingStub(channel);
// 调用存根里的办法
StringValue productID = stub.addProduct(Product.newBuilder()
.setName("Apple iPhone 11")
.setDescription("Meet Apple iPhone 11." +
"All-new dual-camera system with" +
"Ultra Wide and Night mode.")
.build());
整体流程
能够看到,其实接口定义文件 ProductInfo.proto 就是一个粘合剂,它将服务端的逻辑形象成了语言无关的形容文件,让服务端顺次去实现具体逻辑。而后通过它生成的客户端存根(Stub)则屏蔽了底层的通信流程,只须要裸露让下层能够调用的函数即可,就像本地函数调用一样。
其余个性
Metadata(元数据)
gRPC 没有应用 HTTP 所谓的 header 字段,而是应用 Metadata 来构建相干的头部信息。Metadata 是在一次 RPC 调用过程中对于这次调用的信息,以 key-value 的模式存在。
其中 key 是 string 类型,value 也是一组 string。Metadata 对于 gRPC 自身来说通明,它使得 client 和 server 能为对方提供本次调用的信息。就像一次 http 申请的 RequestHeader 和 ResponseHeader,http header 的生命周期是一次 http 申请,Metadata 的生命周期则是一次 RPC 调用。
Streaming(流)
得意于 HTTP/2 的多路复用能力,使得 gRPC 的客户端和服务端可能进行流式传输,例如咱们能够边传输,边解决数据。gRPC 的流式传输次要分为了上面几种:
- 服务端流式 RPC:客户端发送单个申请,服务器能够发回多个响应。
- 客户端流式 RPC:客户端发送多个申请,而服务器只发回一个响应。
- 双向流式 RPC:客户端和服务器同时互相发送音讯而不期待响应。
Interceptors(拦截器)
gRPC 反对在申请 / 响应中应用拦挡性能,进行音讯的拦挡并批改它们,这跟平时咱们提到的 HTTP 中间件十分的类似。基于拦截器,咱们能够实现相似身份认证、链式调用、重试等性能,这些对应微服务是十分的符合的。
负载平衡
gRPC 官网提供了对于负载平衡的计划:Load Balancing in gRPC,有趣味的同学能够本人钻研下。
gRPC 长处
正是后面的 Protobuf 和 HTTP/2 的底层反对,使得 gRPC 在一推出后就受到了许多人的追捧,它次要有以下几个特点:
- 性能:比 REST + JSON 快 10 倍的性能,音讯负载小而紧凑,并且通过压缩放慢了传输速度。
- 代码生成:通过语言无关的接口定义文件疾速的生成各种语言的客户端、服务端代码,进步了开发效率。
- 可拓展性好:进步了一体化的 RPC 解决方案,有许多内置的解决方案,例如数据交换、加密、身份验证、超时勾销、拦截器、负载平衡等。
gRPC 的毛病
与其余技术一样,gRPC 有长处也有毛病,上面就是咱们在开发应用程序时须要留神的点:
- 无限的浏览器反对:因为 gRPC 大量应用 HTTP/2,因而无奈之间在 Web 浏览器调用 gRPC 服务,gRPC 比拟实用于手机 APP Client。
- 不敌对格局:Protobuf 将 gRPC 消息压缩成非可读格局,须要反序列化才拿到音讯格局,不好调试。
总结
古代软件应用程序曾经很少孤立存在了,更多是通过网络通信进行服务沟通。gRPC 是一种可拓展、松耦合且类型平安的解决方案.
与传统的基于 REST/HTTP 的通信相比,它能进行更无效的过程间通信,特地是当初风行的微服务架构里,在很多框架里都能看到它的身影存在。所以,是时候开始试试它的魅力所在了!
参考
- [1] The Concept Of GRPC
- [2] Introduction to gRPC
感兴趣的敌人能够搜一搜公众号「阅新技术」,关注更多的推送文章。
能够的话,就顺便点个赞、留个言、分享下,感激各位反对!
阅新技术,浏览更多的新常识。