RPC通信基本原理 -- 浅析RPC远程过程调用基本原理
一、RPC基本概念
1.1、RPC简介
- RPC 的全称是
Remote Procedure Call
是一种进程间通信方式。- RPC只是一个概念 而不是具体的协议或框架。
- 它允许程序调用另一个地址空间(
通常是共享网络的另一台机器上
)的过程或函数,而不用程序员显式编码这个远程调用的细节。- 即程序员无论是调用本地的还是远程的,本质上编写的调用代码基本相同。
- 它可以有不同的实现方式。如
RMI(远程方法调用)、Hessian、Http invoker
等。另外,RPC是与语言无关的。
如上图所示,假设Computer1在调用sayHi()方法,对于Computer1而言调用sayHi()方法就像调用本地方法一样,调用 –>返回。但从后续调用可以看出Computer1调用的是Computer2中的sayHi()方法,RPC屏蔽了底层的实现细节,让调用者无需关注网络通信,数据传输等细节。
1.2、RPC架构
一个完整的RPC架构里面包含了四个核心的组件,分别是Client,Client Stub,Server以及Server Stub,这个Stub可以理解为存根。
- 客户端(
Client
),服务的调用方。 - 客户端存根(
Client Stub
),存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。 - 服务端(
Server
),真正的服务提供者。 - 服务端存根(
Server Stub
),接收客户端发送过来的消息,将消息解包,并调用本地的方法。
1.3 RPC调用过程
(1) 客户端(
client
)以本地调用方式(即以接口的方式
)调用服务;(2) 客户端存根(
client stub
)接收到调用后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对象序列化为二进制
);(3) 客户端通过
sockets
将消息发送到服务端;(4) 服务端存根(
server stub
)收到消息后进行解码(将消息对象反序列化
);(5) 服务端存根(
server stub
)根据解码结果调用本地的服务;(6) 本地服务执行并将结果返回给服务端存根(
server stub
);(7) 服务端存根(
server stub
)将返回结果打包成消息(将结果消息对象序列化
);(8) 服务端(
server
)通过sockets将消息发送到客户端;(9) 客户端存根(
client stub
)接收到结果消息,并进行解码(将结果消息发序列化
);(10) 客户端(
client
)得到最终结果。
RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。
注意
:无论是何种类型的数据,最终都需要转换成二进制流在网络上进行传输,数据的发送方需要将对象转换为二进制流,而数据的接收方则需要把二进制流再恢复为对象。
1.4、作用及优势
1、作用:
- 1、使服务解耦
- 2、分布式设计
- 3、部署灵活
- 4、容易扩展
2、优点:
- 1、一般使用长链接,不必每次通信都要3次握手,减少网络开销
- 2、一般都有注册中心,有丰富的监控管理
- 3、发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作
- 4、协议私密,安全性较高
- 5、rpc 能做到协议更简单内容更小,效率更高
- 6、rpc是面向服务的更高级的抽象,支持服务注册发现,负载均衡,超时重试,熔断降级等高级特性
二、RPC架构解析
2.1、RPC架构分析
RPC的定义:远程过程调用,调用远程就像调用本地某个过程或函数。通过这一句我们是不是感受不到IP等地址信息的存在了,请求头是不是也应该存在了,编码什么的也不复存在了吧,网络传输不应该让我们开发者感受到了吧…中间的所有跟调用过程相关的是不是都是RPC内部应该帮我们做的,那么接下来我们看一下RPC中具体应该有哪些模块,每个模块又有什么存在的意义
-
- 1、调用模块:通过该模块对数据进行封装、对请求进行负载、超时判断、熔断和限流等等
- 2、序列化 : 通过该模块对数据进行序列化,转成可通过网络传输的格式,并在没收到数据后反序列化成可读的格式
- 3、协议编码:这里的编码是对数据的编码和解码
- 4、网络传输:两个服务之间信息的传输
- 5、服务发现:从注册中心订阅服务
- 6、服务注册:将服务提供者提供的服务注册到注册中心供消费者使用
- 7、注册中心:在高可用的生产环境中,服务一般都以集群方式提供服务,集群里面的IP等重要参数信息可能随时会发生变化,节点也可能会动态扩缩容,客户端需要能够及时感知服务端的变化,获取集群最新服务节点的连接信息,而这些变化要求是要对调用方应用无感知的
-
2.2、RPC框架的实现
上面介绍了RPC的核心原理:RPC能够让本地应用简单、高效地调用服务器中的过程(服务)。它主要应用在分布式系统。如
Hadoop
中的IPC组件。但怎样实现一个RPC框架呢?
2.1.1、从下面几个方面思考,仅供参考:
1.通信模型:假设通信的为A机器与B机器,A与B之间有通信模型,在Java中一般基于
BIO
或NIO
;。2.过程(服务)定位:使用给定的通信方式,与确定IP与端口及方法名称确定具体的过程或方法;
3.远程代理对象:本地调用的方法(服务)其实是远程方法的本地代理,因此可能需要一个远程代理对象,对于Java而言,远程代理对象可以使用Java的动态对象实现,封装了调用远程方法调用;
4.序列化,将对象名称、方法名称、参数等对象信息进行网络传输需要转换成二进制传输,这里可能需要不同的序列化技术方案。如:
protobuf,Arvo
等
2.1.2、hdfs的RPC基本流程:
hdfs的rpc流程基本如上,其中的关键就是获得NameNode代理对象。
2.3、JAVA中代理方式
2.2.1、什么是代理模式
1.定义:为其他对象提供一种代理以控制对这个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
2.例子:最开始接触JDBC操作数据库的时候,业务层每一个方法都需要做以下几件事
(1)打开数据库连接
(2)执行我们想要的操作
(3)关闭数据库连接
此时,我的核心业务是第(2)步,其余两步为辅助业务。当核心业务与辅助业务写在了一个方法中时。会出现以下问题:
① 代码业务冗余② 开关数据库连接大量的重复
- 3.通过代理模式,我们可以抽取出核心业务与辅助业务
2.2.2、静态代理与动态代理
对 JAVA 来说就是使用代理!java代理有两种方式
- (1)静态代理
先定义一个公共接口,里面包括了可以通过RPC调用的方法列表。而且被代理对象以及对象本身都需要实现该接口
尽管字节码生成方式实现的代理更为强大和高效,但代码不易维护,大部分公司实现RPC框架时还是选择动态代理方式
- (2)动态代理
先定义一个公共接口,里面包括了可以通过RPC调用的方法列表。被代理对象以及对象本身都不需要实现该接口。而是通过匿名内部类+反射的机制实现。hadoop就是使用这种方式。
1.实现
InvocationHandle
接口,该接口所在位置为:java.lang.reflect.InvocationHandler
2.该接口中有一个方法
Object invoke(Object proxy, Method method, Object[] args)
(1)
Ojbect proxy
:表示需要代理的对象(2)
Method method
:表示要操作的方法(3)
Object[] args:method
方法所需要传入的参数(可能没有为,null.也可能有多个)3.代理类
java.lang.reflect.Proxy
(Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类)4.调用代理类中的方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException参数:(1)loader - 定义代理类的类加载器(2)interfaces - 代理类要实现的接口列表(3)h - 指派方法调用的调用处理程序返回:一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
2.4、hadoop RPC框架的例子
Server:
/*
MyInterface.java
*/
package Server;import org.apache.hadoop.ipc.VersionedProtocol;public interface MyInterface extends VersionedProtocol {public static long versionID = 1001; //这个是标记RPC的client和server对应的标记public String helloWorld(String name);
}/*
MyImpl.java
*/
package Server;import org.apache.hadoop.ipc.ProtocolSignature;import java.io.IOException;public class MyImpl implements MyInterface{/*这是实际目标*///重写我们在上面接口自定义的方法@Overridepublic String helloWorld(String name) {return "hello," + name;}//返回版本号@Overridepublic long getProtocolVersion(String s, long l) throws IOException {return MyInterface.versionID;}//返回签名信息@Overridepublic ProtocolSignature getProtocolSignature(String s, long l, int i) throws IOException {return new ProtocolSignature(MyInterface.versionID, null);}
}/*
MyRpcServer.java
*/
package Server;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;import java.io.IOException;public class MyRpcServer {public static void main(String[] args) {//建立rpc通道对象RPC.Builder builder = new RPC.Builder(new Configuration());//设置RPC server参数builder.setBindAddress("localhost");builder.setPort(7788);//部署程序,传入实现server业务代码的接口定义,这里面包括了该rpcserver 可以提供的方法,也就是给client调用的方法列表,通过反射的方式引入类对象builder.setProtocol(MyInterface.class);//部署接口的实现类对象builder.setInstance(new MyImpl());//开启servertry {RPC.Server server = builder.build();server.start();} catch (IOException e) {e.printStackTrace();}}
}
client:
/*
MyRpcClient.java
*/
package Client;import Server.MyInterface;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;import java.io.IOException;
import java.net.InetSocketAddress;public class MyRpcClient {public static void main(String[] args) {try {//获取代理对象,设置接口类对象、RPC通信的versionID,rpcserver地址、configuration对象MyInterface proxy = RPC.getProxy(MyInterface.class,MyInterface.versionID,new InetSocketAddress("localhost", 7788),new Configuration());//获得代理对象之后,就可以通过proxy调用接口类中的方法,这里就调用上面定义的 helloWorld对象System.out.println(proxy.helloWorld("king"));} catch (IOException e) {e.printStackTrace();}}
}
下面启动server端和client端,执行结果为:
//server:可以看到显示监听端口 7788
[main] INFO org.apache.hadoop.ipc.CallQueueManager - Using callQueue: class java.util.concurrent.LinkedBlockingQueue queueCapacity: 100 scheduler: class org.apache.hadoop.ipc.DefaultRpcScheduler
[Socket Reader #1 for port 7788] INFO org.apache.hadoop.ipc.Server - Starting Socket Reader #1 for port 7788
[IPC Server Responder] INFO org.apache.hadoop.ipc.Server - IPC Server Responder: starting
[IPC Server listener on 7788] INFO org.apache.hadoop.ipc.Server - IPC Server listener on 7788: starting//client: 我们传入“King”作为参数,能够争取执行
hello,king
RPC通信基本原理 -- 浅析RPC远程过程调用基本原理相关推荐
- c++socket多个客户端通过不同端口与一个服务端通信_手写RPC,深入底层理解整个RPC通信...
一.前言 RPC,远程过程调用,调用远程方法像调用本地方法一样.RPC交互分为客户端和服务端,客户端调用服务端方法,服务端接收数据并打印到控制台,并response响应给客户端. RPC和HTTP的联 ...
- 10个类手写实现 RPC 通信框架原理
作者:Autu autumn200.com/2020/06/21/write-rpc/ 什么是rpc RPC:remote procedure call Protocol 远程过程调用 调用远程服务, ...
- Python标准库asyncio模块基本原理浅析
Python标准库asyncio模块基本原理浅析 本文环境python3.7.0 asyncio模块的实现思路 当前编程语言都开始在语言层面上,开始简化对异步程序的编程过程,其中Python中也开始了 ...
- 消息中间件—RocketMQ的RPC通信(二
作者:胡宗棠 来源:匠心独运的博客 在(一)篇中主要介绍了RocketMQ的协议格式,消息编解码,通信方式(同步/异步/单向).消息发送/接收以及异步回调的主要通信流程.而本篇将主要对RocketMQ ...
- 深入剖析通信层和RPC调用的异步化(上)
<Netty 进阶之路>.<分布式服务框架原理与实践>作者李林锋深入剖析通信层和 RPC 调用的异步化.李林锋此后还将在 InfoQ 上开设 Netty 专题持续出稿,感兴趣的 ...
- linux 中rpc 服务器,实现Linux环境下编程RPC通信之个人经验总结(转)
#include #include "trans.h" char * readfile(char *); static char * retcode; char ** readfi ...
- openstack RPC通信
http://www.cnblogs.com/chenergougou/p/7056557.html openstack RPC通信 OpenStack 的主要组件有 Nova.Cinder.Neut ...
- RPC通信框架——RCF介绍
现有的软件中用了大量的COM接口,导致无法跨平台,当然由于与Windows结合的太紧密,还有很多无法跨平台的地方.那么为了实现跨平台,支持Linux系统,以及后续的分布式,首要任务是去除COM接口. ...
- 嵌入式软件算法之卡尔曼滤波基本原理浅析
卡尔曼滤波基本原理浅析 前言 一.卡尔曼滤波介绍 二.基本原理 2.1 测量值与估计值的权重配置 2.2 高斯分布数学模型的描述 2.3 基于高斯分布模型的迭代 三.一阶卡尔曼滤波 3.1温度示例模型 ...
最新文章
- 2021年大数据ELK(十一):Elasticsearch架构原理
- 整理的一点MD5资料(第一部分)
- 4.QT4中的connect的实现
- Android的px、dp和sp
- 机器学习-损失函数 (转)
- linux程序实例获取,Linux命令备忘实例(4)——获取内容
- [python] redis 模块 -- 实现 python 与 Redis 数据库的结合
- 首届React开发者大会于2018年8月18日在广州举办
- 常用位操作以及相关原理
- 微软Edge/IE11浏览器将禁用SHA-1证书网站
- L1-037 A除以B (10 分)—团体程序设计天梯赛
- Away3D 的实体收集器流程2
- 供应XBF-01型多功存储介质粉碎机
- 【车道线检测与寻迹】2月24日 CVST工具箱模块仿真与图像处理(二)、基于Vision对象的边缘检测、余弦变换压缩,与峰值信噪比
- Swift - 实现tableView单选系统样式
- CC2500模块移植说明
- edge 打开PDF文件显示无法加载插件
- 京牌车辆过户以后车辆保险怎么办?
- LeetCode题解(0695):岛屿的最大面积(Python)
- php每30分钟计算一次收益,PHP 计算用户的累计收益