一文掌握gRPC

1. gRPC简介

gRPC是由google开源的高性能的RPC框架。它是由google的Stubby这样一个内部的RPC框架演化出来,gRPC2015年开源,目前是在云原生时代的一个RPC的标准。

gRPC的核心设计思路:

  • 协议:使用Http2协议(传输数据使用二进制数据内容、支持双向流[双工]、连接的多路复用)
  • 序列化:基于二进制(protobuf- 谷歌开源的一种序列化方式)
  • 代理的创建 :让调用者像调本地方法一样去调用远端的方法

Thrift和gRPC的区别:首先Thrift和gRPC这两个RPC框架有一个共性,就是都支持异构语言的RPC

  • 网络通信层面:Thrift自己定义了自己的协议,直接基于TCP协议,而gRPC的协议是HTTP2的协议
  • 性能角度:ThriftRPC的效率是高于gRPC
  • gRPC是大厂背书(google),云原生时代gRPC与其它组件合作的更加好,所以gRPC应用的更广泛

gRPC的优点:

  • 能够高效的进行进程间通信(协议+序列化)
  • 支持多种语言,对主流的语言提供了原生的支持(C、GO、Java)
  • 支持多平台运行(Linux、Android、IOS、Mac1OS、Windows)
  • grpc序列化方式使用prorubuf、效率高
  • 使用Http2协议
  • google大厂背书

2. Http2.0协议

回顾HTTP1.x协议

  • Http1.0协议:基于请求响应的模式,并且是一个短连接(无状态的协议),传输文本格式的数据,并且是单工的(只有客户端找服务端,而无法实现服务端的主动推送)。

这里思考一个问题:Http底层使用TCP协议,TCP是一个长连接协议,为什么Http1.0是一个短连接协议?

因为HTTP1.0的短连接是自己的设计造成的,一次数据发送完毕就会主动断开,导致了Http1.0是一个短连接协议。这种设计是因为当时服务器性能较差,无法支持维持大量的长连接。

  • Http1.1协议:基于请求响应模式,但它支持有限的长连接(保持一段时间,一段时间Keepalived字段后自动断开连接),基于此出现了WebSocket技术。

总结:Http1.x协议它们传输数据都是文本格式(Http1.1请求体可以是二进制数据),可读性好但是效率低。Http1.x协议无法实现双工通信。Http1.x资源请求时,需要发送多个请求,建立多个连接(比如客户端从服务端拿一个网页,一次请求拿到了这个页面,但是这个页面如果里面有超链接、和CSS以及js资源,而这写资源又要发送新的请求,所以需要建立多个连接)

Http2.0协议

  • Http2.0协议是一个二进制协议,传输效率高于Http1.x协议,但是二进制可读性差
  • 可以实现双工通信
  • 一个请求可以请求多次和多个数据(多路复用)

为什么Http2.0可以实现多路复用?

Http2.0抽取了3个重要的概念,分别是数据流(Stream)、消息(Message)和帧(Frame),这三个概念有机的整合在一起就可以实现多路复用。

在这里插入图片描述

  1. Http2.0发送的一个数据时是以一个Stream为宏观单位的,例如一个连接上有3个数据流(Stream),每个数据流代表我们请求的一个功能。假如在Http1.x协议中,我们请求一个页面首先会请求到一个HTML页面,然后就会异步的发送两个请求来请求CSS资源和JS资源,所以需要三个连接。而在Http2.0中它会复用一个连接,创建3个Stream流,一个Stream流负责获取HTML页面,另一个Stream流负责获取CSS资源而最后一个Stream流负责获取JS资源,重要的是这三个Stream流会放在一个连接上(连接复用)。
  2. 而一个Stream中会有一个Message,这个Message里面会有两个frame,一个frame放置请求头,一个frame放置请求体
  3. 同时响应也可以有多个Stream

在这里插入图片描述

其它概念:

  1. 数据流的优先级:各个Stream有优先级,通过给不同的Stream设置权重,来限制不同流的传输顺序
  2. 可以做流控,如果客户端的流的发送速度大于服务端处理数据,导致服务端处理不过来,此时服务端可以通知客户端暂时停止发送流

3. 序列化-Protobuf

Protobuf是一种与编程语言无关(它自己定义的IDL语言),与平台无关(操作系统)。它定义了中间语言,可以方便在客户端和服务端中进行RPC传输。Protobuf有两种协议版本,一个是Protobuf2一个是Protobuf3,目前主流使用的是Protobuf3。在使用Protobuf的过程中我们需要按照Protobuf的编译器,这个编译器的作用就是可以把Protobuf的IDL的语言转换为具体某一种开发语言。

  • Protobuf编译器的安装

安装网址:https://github.com/protocolbuffers/protobuf/releases

在这里插入图片描述
在这里插入图片描述

idea同时安装Protobuf插件,方便开发。

注意2021.2版本后的idea是内置了Protobuf插件的,老版本可以选装ProtoBuf版本,但是二者是不能共存的

在这里插入图片描述

  • Protobuf基本使用(Protobuf3)

文件格式:Protobuf所有的内容都需要写在一个.proto文件中

版本设定:.proto文件的第一行,syntax="proto3";

注释:

  • 单行注释://
  • 多行注释:/**/

与java语言相关的语法:

//后续protobuf生产的java代码是一个源文件还是多个源文件
option java_multiple_files = true/false;
//指定protobuf生产的java源文件放置的位置
option java_package="com.jackiechai";
//指定protobuf生成的java类封装的大类的名称(因为protobuf生成的所有java类都会成为一个大类的内部类)
option java_outer_classname="UserService";

逻辑包:package xxx;用于protobuf对于文件内容的管理

导入:在实际的开发中我们可能有多个.proto,每个.proto管理自己的内容,现在可能出现一个问题,其中一个.proto依赖另一个.proto的内容,这里就需要使用导入语法:import "xxx/Userservice.proto"

在这里插入图片描述

  • ProtoBuf基本类型

官网可以查看ProtoBuf所支持的所有基本类型:https://protobuf.dev/programming-guides/proto3/

  • 枚举类型
enum SEASON{
   
	SPRING = 0;//0和1代表字段的编号
	SUMMER = 1;
}

注意枚举的编号是从0开始的

  • 消息Message
message LoginRequest{
   
	string username = 1;//1对应这个内容在消息中的编号
	string password = 2;
	int32 age = 3;
}

客户端就是通过message来进行信息交流。

编号:编号是1开始到 2 2 9 − 1 2^29-1 2291结束,注意其中19000-19999不能用,这个区间内的编号是protobuf自己保留的

关键字:消息中可以加入两个关键字,singular,这个是修饰消息字段的,可写也可以不写,表示这个字段的值只能是0个或者1个(默认关键字)。

message LoginRequest{
   
	singular string username = 1;//1对应这个内容在消息中的编号
	singular string password = 2;
	singular int32 age = 3;
}

repeated修饰的字段,表示这个字段的返回值是多个,等价于java中的list:

message LoginRequest{
   
	string content=1;
	repeated string stutas=2;
}

上面content是singular类型,stutas是repeated类型。

在protobuf中消息是可以嵌套的:

message searchResponse{
   
	message Result{
   
		string url=1;
		string title=2;
	}
	string xxx=1;
	int32 yyy=2;
	Result ppp=3;
}

message AAA{
   
	string xxx=1;
	searchResponse.Result yyy=2;
}

oneof关键字,如下我们在使用test_oneof对象时,我们只能代表它的值之一,例如test_oneof可以代表name或者代表age。

message simpleMessage{
   
	oneof test_oneof{
   
		string name=1;
		int32 age=2;
	}
	test_oneof xxxx=1;
}
  • 服务的定义
service HelloService{
   
	//LoginRequest和HelloResponse就是前面的Message
	rpc hello(LoginRequest) returns(HelloResponse){
   
	  		//hello就相当于一个服务接口,具体的服务逻辑是服务提供方来实现的
	} 
}

一个服务,例如上面HelloService,里面是可以定义多个服务方法的,而且根据我们的需要我们是可以定义多个服务的。对于gRPC来说它的服务方式是分成4种情况的,这里先不详细分析。

4. gRPC开发实战环境搭建

  • 项目结构
  1. xxxx-api模块:定义protobuf的idl语言,并且通过命令来创建具体的代码,后序服务端和客户端引入使用(客户端和服务端公共模块),包括定义message和service
  2. xxxx-server模块:服务提供方模块。实现API模块中定义的接口,需要和具体的业务相结合。然后发布整个gRPC服务(创建服务端程序)
  3. xxxx-client模块:创建服务端的代理,基于这个代理来进行RPC调用
  • API模块开发
  1. 创建API模块

在这里插入图片描述
2. 编写proto文件

syntax = "proto3";

option java_multiple_files = false;
option java_package = "com.jackie";
option java_outer_classname = "HelloProto";


/**
  发布RPC服务
 */
//定义请求消息
message HelloRequest{
   
  string name = 1;
}

//定义响应消息
message HelloResponse{
   
  string result = 1;
}


/**
 开发service
 */
service HelloService{
   
  rpc hello(HelloRequest) returns (HelloResponse){
   
    
  }
}

在这里插入图片描述
3. 将ProtoBuf的IDL内容转换为具体使用的语言的代码(protoc这个编译器完成的,它可以将这个IDL语言转换为我们使用的目标语言),所以我们要做的就是将这个proto文件进行编译:

protoc --java_out=/***/***  /***/***/***.proto
#--java_out=:表示生成java代码
# /***/***:生成的代码文件放的位置
#/***/***/***.proto:定义好的proto文件

上面是编译命令,但这种方式需要频繁的使用终端所以不适合开发。下面看看我们怎么在开发中怎么使用:

其实我们可以使用Maven插件来进行protobuf IDL文件的编译操作。首先我们需要引入相关的依赖:

<dependencies>
<!--       grpc-netty-shaded说明grpc底层通信使用的是netty框架-->
        
为了在Python 2环境下安装并使用grpcio_testing库进行gRPC接口测试,请参照以下步骤: 参考资源链接:[Python后端库grpcio_testing 1.38.1版本发布](https://wenku.csdn.net/doc/6sfvdmtkvm) 首先,确保你有Python 2的环境和pip工具。由于Python 2已经停止官方支持,建议在虚拟环境中进行开发,以避免与系统级别的其他Python依赖冲突。 接下来,你可以从提供的资源链接下载grpcio_testing-1.38.1-py2-none-any.whl安装包。下载完成后,使用pip安装该包: ```bash pip install grpcio_testing-1.38.1-py2-none-any.whl ``` 安装完成后,你可以开始编写测试用例。以下是一个简单的gRPC接口测试示例: ```python import grpc from grpc_health.v1 import health from grpc_health.v1 import health_pb2 from grpc_health.v1 import health_pb2_grpc def run_test(): # 创建gRPC通道 channel = grpc.insecure_channel('***.*.*.*:50051') # 连接到gRPC服务 stub = health_pb2_grpc.HealthStub(channel) # 调用HealthCheck服务 response = stub.Check(health_pb2.HealthCheckRequest(service='YourServiceName')) # 检查服务状态 if response.status == health_pb2.HealthCheckResponse.SERVING: print('Service is healthy!') else: print('Service is not healthy.') if __name__ == '__main__': run_test() ``` 在这个示例中,我们连接到了运行在本地50051端口上的gRPC服务,并对特定的服务名称进行了健康检查。如果你是gRPC服务的开发者,可以通过编写类似这样的测试脚本来验证服务的可用性和稳定性。 完成后,你可以参考《Python后端库grpcio_testing 1.38.1版本发布》一文,了解该库的其他功能和使用方法。为了深入理解gRPC和Protocol Buffers的更多细节,建议查看gRPC官方文档和Protocol Buffers的使用指南,这将有助于你进一步掌握gRPC接口测试的高级技巧。 务必注意,虽然Python 2版本的库在一些遗留项目中仍然被使用,但新项目推荐使用Python 3。Python 3在语言设计和性能上都有显著的提升,能够提供更好的开发体验和运行时表现。 参考资源链接:[Python后端库grpcio_testing 1.38.1版本发布](https://wenku.csdn.net/doc/6sfvdmtkvm)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值