gRPC定义
gRPC,全程是Google Remote Procedure Call,是由Google开发并开源,是一种高性能、通用的开源远程过程调用RPC框架。
gRPC原理
gRPC架构由以下几个主要组件构成:
1.服务定义(Service Definition)
gRPC使用接口描述语言(IDL)来定义服务接口和消息结构。
IDL提供了一种统一的方式来描述服务和消息,使得不同语言的开发者可以根据IDL生成对应的客户端和服务器端代码。
2.代码生成器(Code Generator)
基于服务定义的IDL文件,gRPC提供了代码生成器工具,可以根据IDL文件自动生成客户端和服务器端的代码。
生成的代码包含了接口的实现、序列化和反序列化的逻辑,提供了对应语言的API和运行时支持。
3.传输层(Transport Layer)
gRPC使用HTTP/2作为底层的传输协议,HTTP/2是一种二进制协议,相比于传统的HTTP/1.x协议,它具有更低的延迟和更高的吞吐量。
HTTP/2支持多路复用,允许多个请求和响应在同一个TCP连接上同时进行,减少了网络连接的开销。
4.序列化和反序列化(Serialization/Deserialization)
gRPC使用Protocol Buffers(ProtoBuf)作为默认的序列化和反序列化机制。
ProtoBuf是一种轻量级的结构化数据交换格式,能够将结构化数据序列化为二进制格式进行传输。
5.服务器端(Server)
gRPC服务器端负责接收和处理客户端发起的RPC请求。
服务器端根据服务定义生成的代码实现服务接口中的方法,并根据接收到的请求进行相应的处理。
6.客户端(Client)
gRPC客户端负责发起RPC请求并接收服务器端的响应。
客户端根据服务定义生成的代码调用相应的方法,并将请求参数传递给服务器端。
gRPC工作流程
与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法,包含参数和返回类型。
在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用,在客户端拥有一个存根能够像服务端一样的方法。
远程过程调用流程图,如下图所示:
主要会包含如下步骤:
- 调用客户端句柄,执行传送参数;
- 调用本地系统内核发送网络消息;
- 消息传送到远程主机上;
- 服务器句柄得到消息并取得参数;
- 执行远程过程;
- 执行的过程将结果返回服务器句柄;
- 服务器句柄返回结果,调用远程系统内核;
- 消息传回本地主机上;
- 客户端句柄由内核接收消息;
- 客户接收句柄返回的数据。
RPC使用示例
下面是一个简单的RPC使用示例,以展示客户端和服务器端之间的远程过程调用。
1.定义服务接口和消息结构
创建一个名为Calculator.proto
的ProtoBuf文件,其中定义了一个计算器服务的接口和消息结构。
syntax = "proto3"; package com.example.grpc; service Calculator { rpc Add(AddRequest) returns (AddResponse) {} } message AddRequest { int32 operand1 = 1; int32 operand2 = 2; } message AddResponse { int32 sum = 1; }
2.生成代码
使用 Protocol Buffer 编译器 protoc
来生成Java代码。
protoc --java_out=. Calculator.proto
3.实现服务接口
package com.example.grpc; import io.grpc.stub.StreamObserver; public class CalculatorImpl extends CalculatorGrpc.CalculatorImplBase { @Override public void add(AddRequest request, StreamObserver<AddResponse> responseObserver) { int sum = request.getOperand1() + request.getOperand2(); AddResponse response = AddResponse.newBuilder().setSum(sum).build(); responseObserver.onNext(response); responseObserver.onCompleted(); } }
4.启动 gRPC 服务器
package com.example.grpc; import io.grpc.Server; import io.grpc.ServerBuilder; import java.io.IOException; public class Server { public static void main(String[] args) throws IOException, InterruptedException { Server server = ServerBuilder.forPort(50051) .addService(new CalculatorImpl()) .build(); server.start(); System.out.println("Server started on port 50051"); server.awaitTermination(); } }
5.创建 gRPC 客户端
package com.example.grpc; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; public class Client { public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051) .usePlaintext() .build(); CalculatorGrpc.CalculatorBlockingStub stub = CalculatorGrpc.newBlockingStub(channel); AddRequest request = AddRequest.newBuilder() .setOperand1(5) .setOperand2(3) .build(); AddResponse response = stub.add(request); System.out.println("Sum: " + response.getSum()); channel.shutdown(); } }
在上述示例中,我们创建了一个 gRPC 服务器,并实现了计算器服务的接口。然后,我们创建了一个 gRPC 客户端,使用该客户端向服务器发送 AddRequest
请求,并接收 AddResponse
响应。
mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!

后台回复【架构】即可获取《阿里架构师进阶专题全部合集》,后台回复【面试】即可获取《史上最全阿里Java面试题总结》