问题背景
公司内部分布式微服务更常用GRPC框架进行通信,因为约定好了各个接口的协议,开发会更有效率,保存一份接口文档也容易查看
- http是应用层协议,tcp是传输层协议
- tcp是以二进制数据流进行传输,上层应用开发不友好,所以出现了http协议
- RPC (Remote Procedure Call)即远程过程调用,是分布式系统常见的一种通信方法。GRPC是Google的RPC框架,方便开发
- http用于接口较少、系统交互少的情况
- GRPC比HTTP更多的优势在于,动态扩展、统一化、安全性、服务法治理等,分布式微服务项目RPC通信是首选,而GRPC又是RPC中的首选框架之一
- GRPC使用http2协议建立通信通道,内容交换格式使用protobuf,微服务之间只需要商定好proto文件,通过使用protobuf插件即可通信
HTTP2相对于HTTP1的优势:
- HTTP2使用的是二进制传送,HTTP1.X是文本(字符串)传送
- HTTP2支持多路复用
- HTTP2头部压缩
- HTTP2支持服务器推送
注意事项 - 默认已安装JDK环境
- 可以通过本文的代码自己创建工程,也可以下载测试源码参考
项目搭建
1 引入pom依赖,包括grpc框架jar包和相关插件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>a.b.c</groupId>
<artifactId>grpc-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<grpc.version>1.34.1</grpc.version><!-- CURRENT_GRPC_VERSION -->
<protobuf.version>3.12.0</protobuf.version>
<protoc.version>3.12.0</protoc.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--grpc和protobuf依赖-->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<!--protobuf插件-->
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</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>
<!--proto文件存放的位置,使用protobuf才能找到-->
<protoSourceRoot>src/main/resources/proto</protoSourceRoot>
<!--通过插件生成的协议代码存放地址-->
<outputDirectory>${basedir}/src/main/java</outputDirectory>
<!--如果放在src下面,一定要false,不然你的代码都没了,输出放在resources就没关系-->
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2 proto文件编写,proto3是没有required和optional字段的
syntax = "proto3";
package a.b.c.grpc;
//插件生成包所在的位置,与package效果一样
//option java_package = "a.b.c.grpc";
//生成服务名字,默认为service名加上Grpc组合的字符串
//option java_outer_classname = "AddServiceGrpc";
option java_multiple_files = true;
service AddService{
rpc add(AddRequest) returns (AddResponse){}
}
message AddRequest{
string requestId = 1;
int32 a = 2;
int32 b = 3;
repeated int32 c = 4;
map<int32, int32> m = 5;
Digits digits = 6;
}
message Digits{
int32 d = 1;
int32 e = 2;
}
message AddResponse{
string requestId = 1;
int32 res = 2;
}
3 使用protobuf插件生成GRPC通信类,在maven插件中,点击Plugins,然后点击protobuf,然后点击protobuf:compile和compile-custom,如下图所示
4 生成grpc通信类
5 模拟微服务客户端
package a.b.c.client;
import a.b.c.grpc.AddRequest;
import a.b.c.grpc.AddResponse;
import a.b.c.grpc.AddServiceGrpc;
import a.b.c.grpc.Digits;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.*;
/**
* @author suolong
* @date 2022/1/14 16:28
*/
public class AddClient {
AddServiceGrpc.AddServiceBlockingStub stub;
ManagedChannel channel;
public static void main(String[] args) {
int a = 101;
int b = 102;
AddClient client = new AddClient();
String requestId = UUID.randomUUID().toString().replaceAll("-", "");
List<Integer> c = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
c.add(i);
}
Map<Integer, Integer> map = new HashMap<>();
map.put(11,33);
Digits digits = Digits.newBuilder()
.setD(147)
.setE(258)
.build();
AddRequest addRequest = AddRequest.newBuilder()
.setRequestId(requestId)
.setA(a)
.setB(b)
.addAllC(c)
.putAllM(map)
.setDigits(digits)
.build();
try {
AddResponse response = client.stub.add(addRequest);
System.out.println("requestId: " + response.getRequestId());
System.out.println("res: " + response.getRes());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public AddClient() {
channel = ManagedChannelBuilder
.forAddress("127.0.0.1", 9090)
.usePlaintext()
.build();
//桩子,封装参数,以网络的形式传给服务端
stub = AddServiceGrpc.newBlockingStub(channel);
}
}
6 模拟微服务服务端
package a.b.c.server;
import a.b.c.grpc.AddRequest;
import a.b.c.grpc.AddResponse;
import a.b.c.grpc.AddServiceGrpc;
import io.grpc.ServerBuilder;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author suolong
* @date 2022/1/14 16:24
*/
public class AddServer extends AddServiceGrpc.AddServiceImplBase {
public static void main(String[] args) throws IOException {
ServerBuilder.forPort(9090)
.addService(new AddServer())
.build()
.start();
System.out.println("server start at 9090");
while (true) {
}
}
@Override
public void add(AddRequest request, StreamObserver<AddResponse> responseObserver) {
//System.out.println(request.getRequestId().getClass());
if (request.getRequestId().equals("")) {
responseObserver.onError(Status.INVALID_ARGUMENT.withDescription("requestId is null").asRuntimeException());
responseObserver.onCompleted();
}
System.out.println("requestId: " + request.getRequestId());
System.out.println("a: " + request.getA());
System.out.println("b: " + request.getB());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < request.getCList().size(); i++) {
sb.append(request.getCList().get(i)).append(" ");
}
System.out.println("c: " + sb);
request.getMMap().forEach((key, value) -> System.out.println("key: " + key + " value: " + value));
System.out.println("D: " + request.getDigits().getD() + " E: " + request.getDigits().getE());
int res = myAdd(request.getA(), request.getB(), request.getCList());
AddResponse response = AddResponse.newBuilder()
.setRequestId(request.getRequestId())
.setRes(res)
.build();
// 返回结果
responseObserver.onNext(response);
// 关闭通道
responseObserver.onCompleted();
}
private int myAdd(int a, int b, List<Integer> c) {
if (!c.isEmpty()) {
System.out.println("I am List");
AtomicInteger res = new AtomicInteger();
c.stream().forEach(x ->
res.addAndGet(x));
return res.get();
} else {
System.out.println("I am single");
return a + b;
}
}
}
7 整个项目文件目录如下
测试步骤
1 先启动server端
2 启动客户端,a=101,b=102,求和,返回为203
心得
- 微服务之间的通信,grpc用起来很方便,微服务之间定好协议,效率更高,可以使用bloomrpc工具自己进行测试
- proto的message顺序,微服务之间一定要对齐,不然会出现不必要的问题
作为程序员第 23 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha …
Lyric: 我醒来还笑着
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/110853.html