在微服务架构中
gRPC 和 REST 是两种主流的通信方式
但由于REST简单易用
很多人至今都没有接触过 gRPC

什么是 gRPC?
gRPC 是 Google 开源的高性能 RPC 框架
什么是 RPC 呢
Remote Procedure Call 远程过程调用
允许A机器上的程序调用B机器上程序的技术
例如 Web Service、Dubbo 就是一种 RPC 的实现
gRPC 基于 HTTP/2 和 Protocol Buffers
能够双向流式通信进行实时数据推送
通过.proto 文件实现强类型接口
传输数据采用二进制格式
比 JSON 更紧凑,性能更高
但调试时需要grpcurl等专用工具
适用于微服务通信、实时系统、高并发场景等
由于存在网络间调用
需要写两部分代码
服务端代码为程序真实的实现
而客户端代码则以接口形式
通过 stub 进行调用
在客户端调用时
给程序员的感觉
就是在使用本地类一样

双方通讯使用 Channel
有点类似 Socket 的方式
另外还需要安装 protoc
Protocol Buffers 编译器
可以生成各种语言的代码
辅助我们编写服务端与客户端的程序
到 github 找到 protocolbuffers / protobuf
在 releases 里下载

windows 可以选择 protoc-32.0-rc-1-win64.zip
解压后,将bin目录加到环境变量的path即可
其他系统都有对应的
完成后在命令行输入以下命令验证安装
protoc --version
我们现在写一个服务
假如我有个管理狗的服务
提供查询狗的列表,以及狗的详情等功能
先创建 proto 定义
// src/main/proto/DogService.proto
syntax = "proto3";
option java_package = "com.liaobuqi.grpc";
option java_outer_classname = "DogServiceProto";
option java_multiple_files = true;
// 狗的信息
message Dog {
string id = 1;
string name = 2;
int32 age = 3;
}
// 获取狗列表请求(无参数)
message GetDogsRequest {}
// 获取狗列表响应
message GetDogsResponse {
repeated Dog dogs = 1;
}
// 获取单个狗请求
message GetDogByIdRequest {
string id = 1;
}
// 获取单个狗响应
message GetDogByIdResponse {
Dog dog = 1;
}
// DogService 接口定义
service DogService {
rpc GetDogs (GetDogsRequest) returns (GetDogsResponse);
rpc GetDogById (GetDogByIdRequest) returns (GetDogByIdResponse);
}
pom 引入依赖
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.59.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.59.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.24.1</version>
</dependency>
生成代码
protoc --java_out=src/main/java \
--grpc-java_out=src/main/java \
src/main/proto/DogService.proto
另外也可以用mvn插件生成
这里不表
服务端示例:
public class DogServiceImpl extends DogServiceGrpc.DogServiceImplBase {
@Override
public void getDogs(GetDogsRequest request, StreamObserver<GetDogsResponse> responseObserver) {
Dog dog1 = Dog.newBuilder().setId("1").setName("大黄").setAge(3).build();
Dog dog2 = Dog.newBuilder().setId("2").setName("旺财").setAge(2).build();
GetDogsResponse response = GetDogsResponse.newBuilder()
.addDogs(dog1)
.addDogs(dog2)
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
@Override
public void getDogById(GetDogByIdRequest request, StreamObserver<GetDogByIdResponse> responseObserver) {
String id = request.getId();
Dog dog = Dog.newBuilder().setId(id).setName("小强").setAge(1).build();
GetDogByIdResponse response = GetDogByIdResponse.newBuilder().setDog(dog).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
启动服务端,需要一个main程序
如果有springboot
则可以加进去
@SpringBootApplication
public class GrpcServerApplication {
public static void main(String[] args) throws IOException, InterruptedException {
SpringApplication.run(GrpcServerApplication.class, args);
Server server = ServerBuilder.forPort(50051)
.addService(new DogServiceImpl())
.build();
server.start();
server.awaitTermination();
}
}
客户端只需引用服务端的地址和端口50051
就可以远程访问了
示范代码:
public void testRpc() {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
.usePlaintext()
.build();
DogServiceGrpc.DogServiceBlockingStub stub = DogServiceGrpc.newBlockingStub(channel);
// 调用 getDogs
GetDogsResponse dogsResponse = stub.getDogs(GetDogsRequest.newBuilder().build());
for (Dog dog : dogsResponse.getDogsList()) {
System.out.println("Dog ID: " + dog.getId() + ", Name: " + dog.getName() + ", Age: " + dog.getAge());
}
// 调用 getDogById
GetDogByIdResponse dogByIdResponse = stub.getDogById(GetDogByIdRequest.newBuilder().setId("1").build());
System.out.println("Dog ID: " + dogByIdResponse.getDog().getId() + ", Name: " + dogByIdResponse.getDog().getName());
channel.shutdown();
}
看懂了原理
其实很简单
希望大家都能学会
如果觉得有用记得关注我啊
先别走,请留步
很多小伙伴也关注很久了
我们能与志同道合的朋友畅聊职业发展
分享最新面试机会和题库
以及行业技术方面的交流、摸鱼的经验
保持联系
可以加我的微信
输入aaa2就有红包领
记得加入哦