| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 网络协议 -> 看了我的 RPC 实战,同事拍案叫绝 -> 正文阅读 |
|
[网络协议]看了我的 RPC 实战,同事拍案叫绝 |
1. RPC 1.1 什么是 RPC ? RPC(Remote Procedure Call Protocol)远程过程调用协议,目标就是让远程服务调用更加简单、透明。 RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节,服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 1.2 为什么要用 RPC ? 当我们的业务越来越多、应用也越来越多时,自然的,我们会发现有些功能已经不能简单划分开来或者划分不出来。 此时可以将公共业务逻辑抽离出来,将之组成独立的服务 Service 应用,而原有的、新增的应用都可以与那些独立的 Service 应用 交互,以此来完成完整的业务功能。 所以我们急需一种高效的应用程序之间的通讯手段来完成这种需求,RPC 大显身手的时候来了! 1.3 常用的 RPC 框架
1.4 RPC 的调用流程 要让网络通信细节对使用者透明,我们需要对通信细节进行封装,我们先看下一个 RPC 调用的流程涉及到哪些通信细节: ? ? 编辑切换为居中 添加图片注释,不超过 140 字(可选)
RPC 的目标就是要 2~8 这些步骤都封装起来,让用户对这些细节透明,下面是网上的另外一幅图,感觉一目了然: 2. gRPC 2.1 什么是 gRPC ? gRPC 是一个高性能、通用的开源 RPC 框架,其由 Google 2015 年主要面向移动应用开发并基于 HTTP/2 协议标准而设计,基于 ProtoBuf 序列化协议开发,且支持众多开发语言。 由于是开源框架,通信的双方可以进行二次开发,所以客户端和服务器端之间的通信会更加专注于业务层面的内容,减少了对由 gRPC 框架实现的底层通信的关注。 如下图,DATA 部分即业务层面内容,下面所有的信息都由 gRPC 进行封装。 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 2.2 gRPC 的特点
2.3 gRPC 交互过程 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选)
2.4 Protocol Buffers 你可以理解 ProtoBuf 是一种更加灵活、高效的数据格式,与 XML、JSON 类似,在一些高性能且对响应速度有要求的数据传输场景非常适用。 ProtoBuf 在 gRPC 的框架中主要有三个作用:定义数据结构、定义服务接口,通过序列化和反序列化方式提升传输效率。 为什么 ProtoBuf 会提高传输效率呢? 我们知道使用 XML、JSON 进行数据编译时,数据文本格式更容易阅读,但进行数据交换时,设备就需要耗费大量的 CPU 在 I/O 动作上,自然会影响整个传输速率。 Protocol Buffers 不像前者,它会将字符串进行序列化后再进行传输,即二进制数据。 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 可以看到其实两者内容相差不大,并且内容非常直观,但是 Protocol Buffers 编码的内容只是提供给操作者阅读的,实际上传输的并不会以这种文本形式,而是序列化后的二进制数据,字节数会比 JSON、XML 的字节数少很多,速率更快。 gPRC 如何支撑跨平台,多语言呢 ? Protocol Buffers 自带一个编译器也是一个优势点,前面提到的 proto 文件就是通过编译器进行编译的,proto 文件需要编译生成一个类似库文件,基于库文件才能真正开发数据应用。 具体用什么编程语言编译生成这个库文件呢?由于现网中负责网络设备和服务器设备的运维人员往往不是同一组人,运维人员可能会习惯使用不同的编程语言进行运维开发,那么 Protocol Buffers 其中一个优势就能发挥出来——跨语言。 从上面的介绍,我们得出在编码方面 Protocol Buffers 对比 JSON、XML 的优点:
Protobuf 也有其局限性:
Protobuf 适用场景:
2.5 基于 HTTP 2.0 标准设计 除了 Protocol Buffers 之外,从交互图中和分层框架可以看到, gRPC 还有另外一个优势——它是基于 HTTP 2.0 协议的。 由于 gRPC 基于 HTTP 2.0 标准设计,带来了更多强大功能,如多路复用、二进制帧、头部压缩、推送机制。 这些功能给设备带来重大益处,如节省带宽、降低 TCP 连接次数、节省 CPU 使用等,gRPC 既能够在客户端应用,也能够在服务器端应用,从而以透明的方式实现两端的通信和简化通信系统的构建。 HTTP 1.X 定义了四种与服务器交互的方式,分别为 GET、POST、PUT、DELETE,这些在 HTTP 2.0 中均保留,我们看看 HTTP 2.0 的新特性:双向流、多路复用、二进制帧、头部压缩。 2.6 性能对比 与采用文本格式的 JSON 相比,采用二进制格式的 protobuf 在速度上可以达到前者的 5 倍! Auth0 网站所做的性能测试结果显示,protobuf 和 JSON 的优势差异在 Java、Python 等环境中尤为明显,下图是 Auth0 在两个 Spring Boot 应用程序间所做的对比测试结果。 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 结果显示,protobuf 所需的请求时间最多只有 JSON 的 20% 左右,即速度是其 5 倍! 下面看一下性能和空间开销对比。 ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 从上图可得出如下结论:
3. gRPC 实战 3.1 项目结构 我们先看一下项目结构: ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 3.2 生成 protobuf 文件 文件 helloworld.proto: syntax = "proto3";option java_multiple_files = true;option java_package = "io.grpc.examples.helloworld";option java_outer_classname = "HelloWorldProto";option objc_class_prefix = "HLW";package helloworld;// The greeting service definition.service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {}}// The request message containing the user's name.message HelloRequest { string name = 1;}// The response message containing the greetingsmessage HelloReply { string message = 1;} 这里提供了一个 SayHello() 方法,然后入参为 HelloRequest,返回值为 HelloReply,可以看到 proto 文件只定义了入参和返回值的格式,以及调用的接口,至于接口内部的实现,该文件完全不用关心。 文件 pom.xml: <?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"> <parent> <artifactId>rpc-study</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>grpc-demo</artifactId> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.14.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.14.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.14.0</version> </dependency> </dependencies> <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>6</source> <target>6</target> </configuration> </plugin> </plugins> </build></project> 这里面的 build 其实是为了安装 protobuf 插件,里面其实有 2 个插件我们需要用到,分别为 protobuf:compile 和 protobuf:compile-javanano,当我们直接执行时,会生成左侧文件,其中 GreeterGrpc 提供调用接口,Hello 开头的文件功能主要是对数据进行序列化,然后处理入参和返回值。
? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 3.3 服务端和客户端 文件 HelloWorldClient.java: public class HelloWorldClient { private final ManagedChannel channel; private final GreeterGrpc.GreeterBlockingStub blockingStub; private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName()); public HelloWorldClient(String host,int port){ channel = ManagedChannelBuilder.forAddress(host,port) .usePlaintext(true) .build(); blockingStub = GreeterGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } public void greet(String name){ HelloRequest request = HelloRequest.newBuilder().setName(name).build(); HelloReply response; try{ response = blockingStub.sayHello(request); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); return; } logger.info("Message from gRPC-Server: "+response.getMessage()); } public static void main(String[] args) throws InterruptedException { HelloWorldClient client = new HelloWorldClient("127.0.0.1",50051); try{ String user = "world"; if (args.length > 0){ user = args[0]; } client.greet(user); }finally { client.shutdown(); } }} 这个太简单了,就是连接服务端口,调用 sayHello() 方法。 文件 HelloWorldServer.java: public class HelloWorldServer { private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); private int port = 50051; private Server server; private void start() throws IOException { server = ServerBuilder.forPort(port) .addService(new GreeterImpl()) .build() .start(); logger.info("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.err.println("*** shutting down gRPC server since JVM is shutting down"); HelloWorldServer.this.stop(); System.err.println("*** server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } // block 一直到退出程序 private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } public static void main(String[] args) throws IOException, InterruptedException { final HelloWorldServer server = new HelloWorldServer(); server.start(); server.blockUntilShutdown(); } // 实现 定义一个实现服务接口的类 private class GreeterImpl extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage(("Hello " + req.getName())).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); System.out.println("Message from gRPC-Client:" + req.getName()); System.out.println("Message Response:" + reply.getMessage()); } }} 主要是实现 sayHello() 方法,里面对数据进行了简单处理,入参为 “W orld”,返回的是 “Hello World”。 3.4 启动服务 先启动 Server,返回如下: ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 再启动 Client,返回如下: ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 同时 Server返回如下: ? 编辑切换为居中 添加图片注释,不超过 140 字(可选) 3.5 项目代码
4. 写在最后 这篇文章详细讲解了 RPC 和 gRPC,以及 gRPC 的应用示例,非常全面,后面会再把 Thrift 整理出来。 这个 Demo 看起来很简单,我 TM 居然搞了大半天,一开始是因为不知道需要执行 2 个不同的插件来生成 protobuf,以为只需要点击 protobuf:compile 就可以,结果发现 protobuf:compile-javanano 也需要点一下。 还有就是我自己喜欢作,感觉通过插件生成 protobuf 不完美,我想通过自己下载的插件,手动生成 protobuf 文件,结果手动生成的没有搞定,自动生成的方式也不可用,搞了半天才发现是缓存的问题,最后直接执行 “Invalidate Caches / Restart” 才搞定。 应征了一句话“no zuo no die”,不过这个过程还是需要经历的。
|
|
网络协议 最新文章 |
使用Easyswoole 搭建简单的Websoket服务 |
常见的数据通信方式有哪些? |
Openssl 1024bit RSA算法---公私钥获取和处 |
HTTPS协议的密钥交换流程 |
《小白WEB安全入门》03. 漏洞篇 |
HttpRunner4.x 安装与使用 |
2021-07-04 |
手写RPC学习笔记 |
K8S高可用版本部署 |
mySQL计算IP地址范围 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/25 22:52:57- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |