一、背景
Spring Cloud分布式微服务应用,通常在微服务之间采用的Feign进行通信,实现简单快捷的调用,底层采用的HTTP形式;相对于gRPC或RPC协议调用来说,性能相对低下,因此我们可以采用开源技术框架gRPC来实现。
微服务开发中,服务间的调用一般有两种方式:Feign或RestTemplate,但在实际使用过程中,尤其是Feign,存在各种限制及局限性,如:HTTP请求方式、返回类型等限制等。服务间调用是非常普遍频繁的,其性能也不是特别理想。
为了解决上述问题,我们采用gRPC方式实现服务间调用,其显著特点就是性能之高(通信采用Netty),通过proto文件定义的接口也是非常清晰而又灵活。
二、gRPC
gRPC是谷歌开源的一个高性能的、通用的RPC框架。和其他RPC一样,客户端应用程序可以直接调用远程服务的方法,就好像调用本地方法一样。它隐藏了底层的实现细节,包括序列化(XML、JSON、二进制)、数据传输(TCP、HTTP、UDP)、反序列化等,开发人员只需要关自业务本身,而不需要关注RPC的技术细节。与其他RPC框架一样,gRPC也遵循定义服务(类似于定义接口的思想)。gRPC客户端通过定义方法名、方法参数和返回类型来声明一个可以被远程调用的接口方法。由服务端实现客户端定义的接口方法,并运行一个gRPC服务来处理gPRC 客户端调用,gRPC客户端和服务端共用一个接口方法。
三、Spring Cloud 整合gRPC
image.png3.1、proto文件定义
新建common项目,存放proto文件,服务端和客户端都依赖此项目。
image.png
*pom依赖
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${grpc.netty.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- 生成proto文件-->
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os.plugin.version}</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf.plugin.version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
*新建helloworld.proto文件,放在:src/main/proto/helloworld.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.gientech.jep.grpc.lib";
option java_outer_classname = "HelloWorldProto";
// The greeting service definition.
service Simple {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
}
}
// The request message containing the user's name.
message HelloRequest {
string code = 1;
string name = 2;
}
// The response message containing the greetings
message HelloReply {
string message = 200;
}
3.2、gRPC 服务端定义
*pom.xml依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
*新建GrpcServerService
@GrpcService
public class GrpcServerService extends SimpleGrpc.SimpleImplBase {
private static Logger logger = LoggerFactory.getLogger(GrpcServerService.class);
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
logger.info("接收到的参数,Code:" + request.getCode() + ",Name:" + request.getName());
HelloReply reply = HelloReply.newBuilder().setMessage("你好, 这是一个grpc调用==> " + "编码:" + request.getCode() + ",名称:" + request.getName()).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
*yml配置
spring:
application:
name: spring-boot-grpc-server
cloud:
consul: #consul注册中心
host: localhost
port: 8500
discovery:
service-name: spring-boot-grpc-server
health-check-path: /actuator/health
health-check-interval: 10s
ip-address: localhost
heartbeat:
enabled: true
prefer-ip-address: true
server:
port: 8080
grpc:
server:
port: 9090
3.3、gRPC 客户端定义
*pom.xml依赖配置
<dependency>
<groupId>com.gientech.jep</groupId>
<artifactId>spring-boot-grpc-common</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- <version>2.0.0.RELEASE</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
*新建GrpcClientService
@GrpcClient("spring-boot-grpc-server")
private SimpleBlockingStub simpleBlockingStub;
/**
* 测试
* @param code 编码
* @param name 名称
* @return
*/
public String sendMessage(String code, String name) {
try {
HelloReply response = simpleBlockingStub.sayHello(HelloRequest.newBuilder().setCode(code).setName(name).build());
return response.getMessage();
} catch (final StatusRuntimeException e) {
return "error: " + e.getStatus().getCode();
}
}
*yml配置
server:
port: 8081
spring:
application:
name: spring-boot-grpc-client
cloud:
consul: #consul注册中心
host: localhost
port: 8500
discovery:
service-name: spring-boot-grpc-client
health-check-path: /actuator/health
health-check-interval: 10s
ip-address: localhost
heartbeat:
enabled: true
prefer-ip-address: true
grpc:
client:
spring-boot-grpc-server: #提gRPC的服务
enableKeepAlive: true
keepAliveWithoutCalls: true
negotiationType: plaintext
Consul和Eureka区别在于替换pom依赖、yml注册地址修改、启动类修改。
源码: 提取码: 28qs
源码:spring-boot-rpc
提取码: 28qs
网友评论