GRPC 压缩算法
这个 RPC 基础设施具有标准化、可通用和跨平台的特点,旨在提供类似 Stubby 的可扩展性、性能和功能,但它主要面向社区。gRPC+提供了多种压缩算法,以满足不同的需求和环境。使用较小的数据尺寸传输需要的带宽更少,这意味着可以减少使用的网络资源和相关费用。Stubby有许多很棒的特性,但无法标准化为业界通用的框架,这是因为它与谷歌内部的基础设施耦合得过于紧密。长期以来,谷歌有一个名为 Stub
RPC:
Remote Procedure Call的简称,中文叫远程过程调用。用于解决分布式系统中服务之间的调用问题。通俗地讲,就是开发者能够像调用本地方法一样调用远程的服务。所以,RPC的作用主要体现在这两个方面:
- 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法;
- 隐藏底层网络通信的复杂性,让我们更专注于业务逻辑的开发。
长期以来,谷歌有一个名为 Stubby 的通用 RPC 框架,用来连接成千上万的微服务,这些微服务跨多个数据中心并且使用完全不同的技术来构建。
Stubby 的核心 RPC 层每秒能处理数百亿次的互联网请求。Stubby有许多很棒的特性,但无法标准化为业界通用的框架,这是因为它与谷歌内部的基础设施耦合得过于紧密。
GRPC:
2015 年,谷歌发布了开源 RPC 框架 gRPC,由google内部的Stubby框架演化而来。这个 RPC 基础设施具有标准化、可通用和跨平台的特点,旨在提供类似 Stubby 的可扩展性、性能和功能,但它主要面向社区。用于减小网络传输数据大小的技术。它将发送的数据压缩为较小的尺寸,以减少带宽占用和提高网络性能。压缩算法可以在数据发送之前对其进行压缩,并在接收端解压缩,使数据能够原样恢复。gRPC+提供了多种压缩算法,以满足不同的需求和环境。这些算法使用不同的压缩技术和策略,例如字典编码、熵编码和预测编码等。根据数据类型、网络带宽和延迟要求等因素,选择合适的压缩算法非常重要。
作用:数据在网络上传输时,需要消耗带宽和时间。高带宽和低延迟的网络连接可以提供快速的数据传输,但是在某些情况下,网络条件可能较差或带宽受限。在这种情况下,压缩算法可以帮助减小数据量,减少传输的时间和网络占用。+压缩算法还可以降低网络传输的成本。使用较小的数据尺寸传输需要的带宽更少,这意味着可以减少使用的网络资源和相关费用。+另外,压缩算法还可以提高整体的网络性能。较小的数据传输量意味着可以更快地完成数据传输,减少了网络延迟和响应时间。这对于实时应用程序和对网络敏感的任务非常重要。
压缩算法
gRPC+提供了多种压缩算法供选择。以下是一些常见的选项:
- gRPC内置的算法:gRPC提供了一些内置的压缩算法,包括Gzip、Deflate和Snappy等。这些算法都是通用的压缩算法,使用起来非常简单,并且可以满足大多数场景的需求。
- brotli:Brotli是一种新兴的开源压缩算法,由Google开发。它能够以更高的压缩比和更低的延迟来减小数据尺寸。Brotli在某些情况下比传统的压缩算法效果更好,特别适用于大数据块的压缩。
- zstd:Zstd是另一种高效的压缩算法,由Facebook开发。它具有可配置的压缩比和压缩速度,可以根据需求进行调整。Zstd在多种应用中都有良好的表现,特别适用于高带宽、高延迟的环境。
- LZ4是一种极快的无损压缩算法,适用于对压缩速度要求较高的场景。它能够以接近硬盘传输速率的速度进行压缩和解压缩,具有出色的性能表现。
以上仅是一些常见的选项,实际上还有其他许多压缩算法可供选择。选取适当的算法需要考虑压缩比、压缩速度、解压缩速度以及资源消耗等因素。
如何选择:
选择合适的压缩算法取决于多个因素。以下是一些参考的指导原则: - 数据类型:不同的数据类型可能对压缩算法有不同的需求。例如,文本数据和二进制数据通常需要不同的压缩策略。因此,需要根据数据类型来选择合适的算法。
- 压缩比和速度:有些场景需要高压缩比,而有些场景则需要更快的速度。根据实际需求选择合适的算法。例如,如果对网络带宽要求不高,但是延迟要求较低,可以选择高压缩比的算法;如果对带宽要求较高,但是压缩速度要求也高,可以选择速度更快的算法。
- 网络条件:考虑网络带宽和延迟对算法选择的影响。如果网络带宽受限,可以选择更高压缩比的算法;如果网络延迟较高,可以选择速度更快的算法。
- 服务和客户端支持:确保选择的算法在服务和客户端上都有良好的支持。一些算法可能需要在服务器和客户端上都进行配置和启用。
核心设计思路
- 网络通信 ------> gRPC 自己封装了网络通信的部分,提供了多种语言的 网络通信的封装,解决异构服务的问题 (CJava[Netty] Go)
- 协议 ------> HTTP2 传输数据的时候 使用二进制的数据内容。支持双向流(双工) 支持连接的多路复用
- 序列化 ------> 数据传输的格式,主要有两种 基于文本(JSON) 基于二进制 java原生的序列化方式,谷歌开源的序列化方式:protubuf:Protocol Buffers 时间和空间效率是JSON的3-5倍 IDL语言
- 代理的创建 ----> 让调用者像调用本地方法那样,去调用远端的服务方法 称为 stub
gRPC优点
- 高效的进行进程间通信 序列化和协议
- 支持多语言 原生支持 C Go Java (一等公民)实现,C语言版本上扩展
- C++,C#,NodeJS,Python等(二等公民)
- 支持多平台运行 GRPC采用protobuf
- 使用HTTP2协议(只有GRPC使用)
在JAVA中使用gRPC
项目结构
1. xxx-api 模块 用于定义protobuf idl语言,并且通过命令创建具体的代码,后续client server引入使用
1. message
2. service
2. xxx-server 模块
1. 实现api模块中定义的服务接口
2. 发布gRPC服务 (创建服务端程序)
3. xxx-client模块
1. 创建服务端stub(代理)
2. 基于代理(stub)进行RPC调用
一、引入依赖
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.21.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.21.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.21.0</version>
</dependency>
</dependencies>
二、引入插件
添加的插件作用是将.proto文件编译为java代码。
插件配置中goals中compile表示编译.proto文件为Message对象,compile-custom表示编译.proto文件为gRPC对象。此插件编译后输出的java代码不在源码目录下,默认位置在打包目录的generated-sources/protobuf/文件夹下,可参考插件官方文档
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.5.0.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.14.0:exe:${os.detected.classifier}</pluginArtifact>
</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>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
若需要将Message源文件和gRPC源文件输出到不同的目录,则可以在maven的配置文件下添加如下配置:
<properties>
<!-- Message源文件输出目录 -->
<javaOutputDirectory>${project.basedir}/src/main/java-proto</javaOutputDirectory>
<!-- gRPC源文件输出目录 -->
<protocPluginOutputDirectory>
${project.basedir}/src/main/java-grpc
</protocPluginOutputDirectory>
</properties>
三、编写服务端代码
1.实现服务端的sayHello方法
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class HelloWorldRpcService extends HelloWorldGrpc.HelloWorldImplBase {
@Override
public void sayHello(Greeting request, StreamObserver<HelloResp> responseObserver) {
String name = request.getName();
HelloResp resp = HelloResp.newBuilder()
.setReply("Hello " + name + "!")
.build();
responseObserver.onNext(resp);
responseObserver.onCompleted();
}
}
2. 创建gRPC的服务端
package com.example.grpc;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
public class GrpcServer {
private Server server;
/**
* @param port 服务端占用的端口
*/
public GrpcServer(int port) {
server = ServerBuilder.forPort(port)
// 将具体实现的服务添加到gRPC服务中
.addService(new HelloWorldRpcService())
.build();
}
public void start() throws IOException {
server.start();
}
public void shutdown() {
server.shutdown();
}
}
四、创建客户端
创建客户端调用Server端的服务
package com.example.grpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
public class HelloWorldClient {
private final HelloWorldGrpc.HelloWorldBlockingStub blockingStub;
/**
* @param host gRPC服务的主机名
* @param port gRPC服务的端口
*/
public HelloWorldClient(String host, int port) {
ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(host, port)
// 使用非安全机制传输
.usePlaintext()
.build();
blockingStub = HelloWorldGrpc.newBlockingStub(managedChannel);
}
public String sayHello(String name) {
Greeting greeting = Greeting.newBuilder()
.setName(name)
.build();
HelloResp resp = blockingStub.sayHello(greeting);
return resp.getReply();
}
}
五、启动测试
编写主类,测试服务端和客户端。
运行如下代码,若无异常,将会输出 Hello, HanMeiMei!。
package com.example.grpc;
public class HelloWorldApp {
public static void main(String[] args) throws Exception {
int port = 8000;
GrpcServer server = new GrpcServer(port);
server.start();
HelloWorldClient client = new HelloWorldClient("localhost", port);
String reply = client.sayHello("HanMeiMei");
System.out.println(reply);
server.shutdown();
}
}
更多推荐
所有评论(0)