Google开发的一个高性能、开源和通用的 RPC 框架,基于ProtoBuf(Protocol Buffers) 序列化协议开发,且支持众多开发语言。面向服务端和移动端,基于 HTTP/2 设计。
- grpc可以跨语言使用。支持多种语言 支持C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP等编程语言
- 基于 IDL ( 接口定义语言(Interface Define Language))文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub;
- 通信协议基于标准的 HTTP/2 设计,支持·双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量;
- 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能。
- 安装简单,扩展方便(用该框架每秒可达到百万个RPC)
1、客户端(gRPC Stub)调用 A 方法,发起 RPC 调用。
2、对请求信息使用 Protobuf 进行对象序列化压缩(IDL)。
3、服务端(gRPC Server)接收到请求后,解码请求体,进行业务逻辑处理并返回。
4、对响应结果使用 Protobuf 进行对象序列化压缩(IDL)。
5、客户端接受到服务端响应,解码请求体。回调被调用的 A 方法,唤醒正在等待响应(阻塞)的客户端调用并返回响应结果。
Grpc(远程过程调用)与HTTP远程调用
①:JDK11(上文也提及基于 HTTP/2,JDK11之后才开始正式使用HTTP/2)
②:Protobuf插件(上文也提及基于protobuf序列化协议,用插件读.proto生成Stub代码)
①:spring-grpc:一个主工程做依赖管理
②:client:Grpc的客户端
③:server:Grpc的服务端
④:grpc-lib:通过.proto文件生成stub的java文件
①:主工程依赖(此处的net.devh的两个starter集成了Grpc的一些繁琐配置,开包即用很方便)
另外感谢yindongnan作者为开源做出的贡献
4.0.0
org.example
spring-grpc
pom
1.0-SNAPSHOT
client
server
grpc-lib
org.springframework.boot
spring-boot-starter-parent
2.1.13.RELEASE
11
11
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
net.devh
grpc-client-spring-boot-starter
2.10.1.RELEASE
net.devh
grpc-server-spring-boot-starter
2.10.1.RELEASE
②:grpc-lib工程依赖(此处完全是抄别人的,主要是配置proto生成的stub路径等等)
spring-grpc
org.example
1.0-SNAPSHOT
4.0.0
grpc-lib
11
11
kr.motd.maven
os-maven-plugin
1.4.1.Final
org.xolstice.maven.plugins
protobuf-maven-plugin
0.5.0
com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}
grpc-java
io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}
${project.basedir}/src/main/java
false
compile
compile-custom
org.codehaus.mojo
build-helper-maven-plugin
3.0.0
add-source
generate-sources
add-source
${project.basedir}/src/main/gen
${project.basedir}/src/main/java
③:server端依赖(没什么特别的,client也雷同)
spring-grpc
org.example
1.0-SNAPSHOT
4.0.0
client
org.example
grpc-lib
1.0-SNAPSHOT
compile
11
11
proto 3 语法不熟悉的可以去查一查
// 基于proto3版本
syntax = "proto3";
option java_multiple_files = true;
// 生成java代码的包路径
option java_package = "com.yuwenwen.grpc";
// grpc服务
service YuWenWenService{
// 一个查询接口
rpc CheckUser(ApiIn) returns (ApiOut) {}
}
// 定义接口入参数
message ApiIn{
string name = 1;
string code = 2;
int64 age =3;
}
// 定义接口返回参数
message ApiOut {
bool success = 1;
string auth=2;
}
此处注意:在grpc-lib的工程下,java包和proto包保持平级。
compile代码之后就会按照指定的路径生成Stub代码
生成完的效果
①:application定义服务端的端口和名称
grpc:
server:
port: 8888
spring:
application:
name: grpc-server
server:
port: 8890
②:业务Service继承生成的java代码
在用工具生成的代码中(YuWenWenServiceGrpc.java)有很多内部类
选择继承 YuWenWenServiceImplBase.java并标注上starter中封装好的@GrpcService注解
注意:responseObserver.onNext方法被调用,可以向客户端输出数据,最后通过 responseObserver.onCompleted结束输出
package com.yu.service;
import com.yuwenwen.grpc.ApiIn;
import com.yuwenwen.grpc.ApiOut;
import com.yuwenwen.grpc.YuWenWenServiceGrpc.YuWenWenServiceImplBase;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class YuWenWenServiceImpl extends YuWenWenServiceImplBase {
@Override
public void checkUser(ApiIn request, StreamObserver responseObserver) {
ApiOut rep = ApiOut.newBuilder().setAuth("admin").setSuccess(true).build();
responseObserver.onNext(rep);
responseObserver.onCompleted();
}
}
这个接口有三个抽象方法,而且命名规则来看是用了观察者模式。
public interface StreamObserver {
void onNext(V var1);
void onError(Throwable var1);
void onCompleted();
}
其中的onNext、onError以及onComplete⽅法均会调⽤内部的ServerCall实例发送消息。 具体发送逻辑实现这⾥不做深⼊,总之可以明确的是,这⾥的StreamObserver回调接⼝,其实现逻辑就是将消息发送⾄客户端,这就是观 察者的逻辑。再看下被观察者,也就是StreamObserver回调接⼝的调⽤⽅。其实就是实现类⾥返回值的⽣成的逻辑,我们需要根据 request取到参数,然后⽣成返回值,调⽤StreamObserver回调接⼝,来通知Grpc框架层发送返回值。⾄此服务端实现⽅法⾥的 StreamObserver已经清晰了:被观察的对象就是返回值,Grpc框架层是观察者,提供发送逻辑作为回调函数,实现类是被观察者,每⼀ 次返回值的⽣成都会调⽤回调函数通知Grpc。还有⼀点,StreamObserver接⼝的定义其实和stream息息相关。我们知道stream模式意 味着可以在⼀个连接中发送多条消息,所以该接⼝提供了onNext回调函数,该函数可以被多次调⽤,每⼀次对onNext的调⽤都代表⼀条消 息的发送。如果全部发送完了或者发送出错,那么就需要调⽤onError或者onComplete来告知对⽅本次stream已经结束。所以该接⼝的设 计也与stream的概念也完全契合。
③:启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
①:依赖Stub代码
RPC(Remote Procedure Call)的中文:远程过程调用
RPC框架追求的就是,两个服务之间的调用就如同调本地方法一样
package com.yuwenwen.controller;
import com.yuwenwen.grpc.ApiIn;
import com.yuwenwen.grpc.ApiOut;
import com.yuwenwen.grpc.YuWenWenServiceGrpc.YuWenWenServiceBlockingStub;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {
@GrpcClient("grpc-server")
YuWenWenServiceBlockingStub yuWenWenStub;
@RequestMapping(value = "/query")
public String queryUser() {
ApiOut apiOut = yuWenWenStub.checkUser(ApiIn.newBuilder().setAge(25).setCode("1124").build());
String result = apiOut.getSuccess() ? "successfully" : "failed";
return result;
}
}
②:application定义客户端和服务端的端口和名称
grpc:
client:
grpc-server:
// # gRPC服务端地址
address: static://localhost:8888
enableKeepAlive: true
keepAliveWithoutCalls: true
negotiationType: plaintext
spring:
application:
name: grpc-client
server:
port: 8891
③:启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
结果:
以上就可以完成一个简易版的Grpc框架以及服务之间的调用