一、RPC介绍
1.1 概述
- RPC(Remote Procedure Call Protocol) 远程过程调用协议。
- RPC是一种通过网络从远程计算机程序上请求服务,不需要了解底层网络技术的协议。
- RPC主要作用就是不同的服务间方法调用就像本地调用一样便捷。
1.2 RPC框架
- 应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
- 远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
- 通信框架:MINA 和 Netty
gRPC:gRPC是Google开源软件,gRPC是基于HTTP2.0协议,而HTTP2.0是基于二进制的HTTP协议升级版本,底层使用Netty框架支持。
Thrift:Thrift是Facebook开源项目,其是一个跨语言的服务开发框架。用户只需在进行二开即可,对底层的RPC通讯透明。
Dubbo:Dubbo是阿里开源组件协议和序列化框架都可以插拔,依托Spring框架开发,远程接口是基于Java接口,适用于微服务架构。
1.3 RPC的作用
1、服务化:微服务化,跨平台的服务之间远程调用;
2、分布式系统架构:分布式服务跨机器进行远程调用;
3、服务可重用:开发一个公共能力服务,供多个服务远程调用;
4、系统间交互调用:两台服务器A、B,服务器A上的应用a需要调用服务器B上的应用b提供的方法,而应用a和应用b不在一个内存空间,不能直接调用,此时,需要通过网络传输来表达需要调用的语义及传输调用的数据。
使用场景
1、大型网站:内部涉及多个子系统,服务、接口较多。
2、注册发现机制:如Nacos、Dubbo等,一般都有注册中心,服务有多个实例,调用方调用的哪个实例无感知。
3、安全性:不暴露资源。
4、服务化治理:微服务架构、分布式架构。
作者这里使用的是第4个用途。
二、RPC架构
RPC的架构图
2.1 调用过程
下面以一次调用过程为例:
1、客户端调用(Client): 通过本地调用的方式调用服务(以接口方式调用);
2、客户端存根(Client Stub): 接收到调用请求后负责将方法、入参等信息进行组装序列化成能够进行网络传输的消息体(将消息体对象序列化为二进制流);
3、客户端存根(Client Stub): 找到远程的服务地址,并且将消息通过网络发送给服务端(通过sockets发送消息);
4、服务端存根(Server Stub): 收到消息后进行反序列化操作,即解码(将二进制流反序列化为消息对象);
5、服务端存根(Server Stub): 通过解码结果调用本地的服务进行相关处理;
6、服务端(Server): 本地服务业务处理(执行应用程序);
7、服务端(Server): 将处理结果返回给服务端存根(返回结果);
8、服务端存根(Server Stub): 序列化处理结果(将结果消息对象序列化为二进制流);
9、服务端存根(Server Stub): 将序列化结果通过网络发送至客户端(通过sockets发送消息);
10、客户端存根(Server Stub): 接收到消息,进行反序列化解码(将结果二进制流反序列化为消息对象);
11、客户端得到最终的结果。
2.2 各部分功能作用
客户端: Client,服务调用方。
客户端存根: Client Stub,存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根: Server Stub,接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端: Server,服务的真正提供者。
**newtwork service:**底层传输,tcp或http
2.3 RPC功能实现
RPC功能的实现主要分为:服务寻址、序列化和反序列化、网络传输功能。
2.3.1 Call ID映射
1、本地:在本地方法调用中,函数体是直接通过函数指针来指定的,但是在远程调用中,由于两个进程的地址空间完全不一样,函数指针不起作用。
2、远程:RPC中所有函数或方法都有自己的一个ID(programID),在所有进程中都唯一。客户端在做远程过程调用时,必须附上这个ID,即客户端会查一下表,找出相应的Call ID,然后传给服务端,服务端也会查表,来确定客户端需要调用的函数,然后执行相应函数的代码。
3、Call ID映射表一般是一个哈希表。
2.3.2 序列化和反序列化功能(类似压缩于解压)
概述
1、序列化:将消息对象转换为二进制流。
2、反序列化:将二进制流转换为消息对象。
必要性
1、远程调用涉及到数据的传输,在本地调用中,只需要将数据压入栈中,然后让函数去栈中读取即可。
2、但远程的数据传输,由于客户端和服务端不在同一个服务器上,涉及不同的进程,不能通过内存传递参数,此时就需要将客户端先将请求参数转成字节流(编码),传递给服务端,服务端再将字节流转为自己可读取格式(解码),这就是序列化和反序列化的过程。反之,服务端返回值也逆向经历序列化和反序列化到客户端。
序列化的优势
1、将消息对象转为二进制字节流,便于网络传输。
2、可跨平台、跨语言。
2.3.3 网络传输功能
作用
1、客户端将Call ID和序列化后的参数字节流传输给服务端。
2、服务端将序列化后的调用结果回传给客户端。
协议
主要有TCP、UDP、HTTP协议。
基于TCP协议(常用)
1、客户端和服务端建立Socket连接。
2、客户端通过Socket将需要调用的接口名称、方法名称及参数序列化后传递给服务端。
3、服务端反序列化后再利用反射调用对应的方法,将结果返回给客户端。
基于HTTP协议
1、客户端向服务端发送请求,如GET、POST、PUT、DELETE等请求。
2、服务端根据不同的请求参数和请求URL进行方法调用,返回JSON或者XML数据结果。
TCP和HTTP对比
1、基于TCP协议实现的RPC调用,由于是底层协议栈,更佳灵活的对协议字段进行定制,可减少网络开销,提高性能,实现更大的吞吐量和并发数。但底层复杂,实现代价高。
2、基于HTTP协议实现的RPC调用,已封装实现序列化,但HTTP属于应用层协议,HTTP传输所占用的字节数比TCP更高,传输效率对比TCP较低。
三、rpcgen工具的使用
3.1 概述
rpcgen
是一个用于生成远程过程调用(RPC)相关代码的工具,它是 RPC 协议的一部分。RPC 是一种允许程序调用另一个地址空间(通常是远程计算机上的程序)中的程序的技术。rpcgen
通常与 UNIX 和类 UNIX 系统上的 RPC 服务一起使用,它可以根据定义 RPC 接口的 .x
文件(接口定义文件)生成客户端和服务器端的代码。
rpcgen工具见 ==> 远程过程调用RPC生成工具
rpcgen
的主要功能包括:
- 自动生成客户端存根(stub)代码,这些代码用于客户端发起 RPC 调用。
- 自动生成服务器端存根代码,这些代码用于服务器端处理 RPC 请求。
- 生成用于数据序列化和反序列化的辅助代码。
- 生成用于错误处理的代码。
使用 rpcgen
时,开发者首先需要定义 RPC 接口定义文件(通常以.x为扩展名),然后在编译时运行 rpcgen
来生成相应的代码。这些代码随后可以被编译和链接到应用程序中,以实现 RPC 功能。
3.2 rpcgen的使用
1、首先我们需要定义 RPC 接口定义文件(通常以.x为扩展名)
2、打开后按照需求定义接口并设定ID
3、然后回到工具所在的地方
4、打开终端,输入命令运行rpcgen.exe,生成.c源文件。
4、执行成功后可以看到生成了新的源文件,生成代码成功。
5、接下来就是将生成的代码移植到需要的地方使用。