本篇文章,我们介绍gRPC并通过例子详细演示使用gRPC的过程。
微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩
1 什么是gRPC.
gRPC是一个开源的、高性能的远程过程调用(RPC)框架,由谷歌提供,用于分布式系统之间的高效通信。它使用协议缓冲区(protobuf)进行有效的数据序列化,并支持双向流、请求/响应流和高级传输功能。在构建微服务架构和其他分布式系统中很受欢迎。
2 gRPC的优势
2.1高性能:
gRPC使用二进制协议,不是像JSON或XML这样的文本协议,这使它在消息大小和处理速度方面更有效率。Portobuff是一种高效的二进制格式,用于结构化数据,具有数据压缩能力。这允许更快的消息序列化和反序列化,并减少服务之间传输数据所需的带宽。
2.2 与语言和平台无关:
gRPC支持多种编程语言和平台,包括C++、Java、Python、Go和其他许多语言。这使它不管使用的是何种技术栈都很容易与现有的系统和服务集成。
2.3 自动代码生成:
gRPC带有代码生成工具,可以自动生成多种编程语言的客户端和服务器代码。这节省了开发人员的时间和精力,并有助于确保代码的一致性和正确性。
2.4 自动代码生成:
gRPC带有一个代码生成工具,可以自动生成多种编程语言的客户端和服务器代码。这节省了开发人员的时间和精力,并有助于确保代码的一致性和正确性。
2.5 流式支持:
gRPC支持单项和流式请求和响应,这使大量数据能进行有效处理和服务间实现实时通信。
2.6 内置支持负载平衡和服务发现:
gRPC包括对负载平衡和服务发现的内置支持,能轻松地构建可扩展、有弹性的分布式系统。
2.7 互操作性:
gRPC支持多种编程语言,使用不同语言编写的服务之间具有互操作性。这有助于现有系统和服务之间的整合,可以减少对复杂和容易出错的API的需求。
3 开始编码
为了便于设置,我为服务器和客户端都添加了模板代码。
你可以按照下面这些链接尝试:
服务器:https://github.com/DeathkillerAnk/grpc-spring-server 客户:https://github.com/DeathkillerAnk/grpc-spring-client
现在开始分解代码库
我们有两个应用程序,一个是服务器,另一个是客户端。
有两个模块service和common。
- 普通模块由proto文件组成,它的作用类似于JSON文件,表示结构化数据,但你可以在.proto文件上运行一个编译器,生成可以用你选择的编程语言读写数据的代码。
- 该服务模块有java和spring boot代码
syntax = "proto3";
package com.deathkiller.grpc;
option java_multiple_files = true;
option java_package = "com.demo.grpc";
service GreetingService {
rpc greeting(GreetingRequest) returns (GreetingResponse) {
}
}
message GreetingRequest {
string message = 1;
}
message GreetingResponse {
string message = 1;
}
在我们的例子中,使用的是Java。因此,当我们运行 "mvn compile "时,它将生成其Java基类,用于实现或调用写在GreetingService服务中的函数。
在服务器端,我们通过重写方法和提供其实现来给问候函数添加逻辑。
package com.demo.grpcdemo.greetingservice;
import com.demo.grpc.GreetingRequest;
import com.demo.grpc.GreetingResponse;
import com.demo.grpc.GreetingServiceGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
@Override
public void greeting(GreetingRequest request, StreamObserver<GreetingResponse> responseObserver) {
String message = request.getMessage();
System.out.println("Received Message: " + message);
GreetingResponse greetingResponse = GreetingResponse.newBuilder()
.setMessage("Received your " + message + ". Hello From Server. ")
.build();
responseObserver.onNext(greetingResponse);
responseObserver.onCompleted();
}
}
由于兼容性问题,gRPC不直接与前端通信。所以它主要用于微服务之间的通信。
我们的客户端将从前端接收请求,客户端将使用gRPC从另一个微服务中获取一些数据,在我们的例子中,它是一个gRPC服务器。
在客户端,我们将为前端暴露一个端点,以使用REST APIs消费我们的服务。
package com.demo.grpcdemo.controller;
import com.demo.grpcdemo.greetingservice.GreetingServiceClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
public class GreetingController {
@Autowired
GreetingServiceClient greetingServiceClient;
@GetMapping("/greet/{id}")
public String getAuthor(@PathVariable String message) {
return greetingServiceClient.greet(message);
}
}
因此,每当我们需要与另一个微服务进行数据通信时,我们应该使用gRPC而不是REST APIs,因为gRPC在接收数据时比REST快7倍,在为特定的有效载荷发送数据时比REST快10倍。这主要是因为协议缓冲区的紧密包装(数据压缩)和gRPC对HTTP/2的使用。
注意:这将取决于数据量。而且,在你的本地客户-服务器通信中,你无法看到明显的差异。
我们来调用在服务器中定义的问候服务。
package com.demo.grpcdemo.greetingservice;
import com.demo.grpc.*;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Service;
@Service
public class GreetingServiceClient {
@GrpcClient("greeting")
private GreetingServiceGrpc.GreetingServiceBlockingStub greetingServiceBlockingStub;
public String greet(String greetingMessage) {
GreetingRequest greetingRequest = GreetingRequest.newBuilder().setMessage(greetingMessage).build();
GreetingResponse greetingResponse = greetingServiceBlockingStub.greeting(greetingRequest);
return greetingResponse.getMessage();
}
}
这只是一个基本的设置。但当你开始向gRPC全面迁移时,你会遇到多种挑战。我在下面提到了其中的一些挑战和它们的解决方案。
- 克服最大有效载荷极限。如果你的传入或传出的信息流量比默认大小太大,那么你将面临错误。需要通过以下办法进行修正:
greetingServiceBlockingStub = greetingServiceBlockingStub.withMaxInboundMessageSize(Integer.MAX_VALUE).withMaxOutboundMessageSize(Integer.MAX_VALUE);
- 使用空值的包装器
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message Foo {
.google.protobuf.Int32Value bar = 1;
}
- 要在Windows上构建proto文件,你需要一个不同的配置。
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message Foo {
.google.protobuf.Int32Value bar = 1;
}
```<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.1.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 以正确的方式进行无效检查
foo.getBar == null //这样做,即使bar从未被设置,也会返回true
foo.hasBar //如果bar被分配为null,则返回false。
推荐书单
Java语言程序设计(第3版)
《Java语言程序设计(第3版)》从初学者角度出发,用通俗易懂的语言、丰富多彩的案例讲述了Java语言的理论知识和编程方法,内容覆盖全国计算机等级考试二级Java语言程序设计的大纲要求,同时融入了新版JDK的特色知识。全书分18章,内容分别是Java语言概述,数据类型与表达式,流程控制语句,数组与方法,类与对象,继承与多态,常用数据类型处理类,抽象类、接口与内嵌类,异常处理,Java绘图,图形用户界面编程基础,流式输入/输出与文件处理、Java泛型与收集API,Lambda表达式、Stream与枚举类型,多线程,高级图形界面编程,JDBC技术与数据库应用,Java的网络编程。读者可以跟随本书的讲解,边学边练,设计出功能较强的中小型应用程序。
《Java语言程序设计(第3版)》(丁振凡,范萍)【摘要 书评 试读】- 京东图书京东JD.COM图书频道为您提供《Java语言程序设计(第3版)》在线选购,本书作者:,出版社:清华大学出版社。买图书,到京东。网购图书,享受最低优惠折扣!https://item.jd.com/13512397.html
精彩回顾
使用JMH提升Java程序的性能
Java中的继承与多态
Markdown Nice最全功能介绍
FPGA的工作原理是什么?
HuggingGPT:解决处理AI任务的秘密武器
微信搜索关注《Java学研大本营》
访问【IT今日热榜】,发现每日技术热点
版权归原作者 Java学研大本营 所有, 如有侵权,请联系我们删除。