RPC(Remote Procedure Call)叫作远程过程调用,它是利用网络从远程计算机上请求服务,可以理解为把程序的一部分放在其他远程计算机上执行。通过网络通信将调用请求发送至远程计算机后,利用远程计算机的系统资源执行这部分程序,最终返回远程计算机上的执行结果。
PRC主要设计五个部分:
服务调用方、调用方的本地存根及其一个RPC通信包的实例存在于调用者的机器上;而服务提供方、服务提供方的存根及另一个RPC通信包的实例存在于被调用的机器上。
服务调用方也叫服务消费者,它的职责之一是提供需要调用的接口的全限定名和方法,调用方法的参数给调用端的本地存根;职责之二是从调用方的本地存根中接收执行结果。
服务提供方就是服务端,它的职责就是提供服务,执行接口实现的方法逻辑,也就是为服务提供方的本地存根提供方法的具体实现。
在远程调用中,对于Consumer发起的函数调用,Provider如何精准的直到自己应该执行哪个函数呢?
这就需要stub了。Stub的存在就是为了让远程调用像本地调用一样直接进行函数调用,无须关系地址空间隔离、函数不匹配等问题。
Stub的职责就是进行类型和参数转化。
本地存根分为服务调用方的本地存根和服务提供方的本地存根。
服务调用方的本地存根和服务消费者都属于Consumer端,它们存在于同一台机器上,服务调用放的本地存根会接收Consumer的函数调用,本地存根会解析函数调用的函数名、参数等信息,整理并且组装这些数据,然后将这些数据安装定义好的协议进行序列化,打包成可传输的消息,交给RPCRuntime(RPC通信者)。服务调用方的本地存根除了会处理服务消费者提供的方法、参数、方法参数类型等数据,还会处理服务提供方返回的结果,它会将RPCRuntime返回的数据反序列化成服务调用方所需要的数据结果并传递给服务消费方。
从服务消费方的角度来看,Stub隐藏了远程调用的实现细节,就像是远程服务的一个代理对象,可以让服务消费方感觉调用远程服务方法就像调用本地方法一样。
服务提供方的本地存根与服务提供方都属于Provider端,它们一起存在于同一台机器上。当Provider端的RPCRuntime收到请求包后,交由服务提供方的本地存根进行参数等数据的转化。服务提供方的本地存根会重新转换客户端传递的数据,以便在Provider端的机器上找到对应的函数,传递正确的参数数据,最终正确地执行真实函数的调用。等函数执行完成后,服务提供方会将执行结果返回给服务提供方的本地存根,由本地存根再将结果数据序列化、打包,最后交给RPCRuntime。服务提供方的本地存根与服务调用方的本地存根一样都是充当了翻译员的角色。
RPCRuntime负责数据包的重传,数据包的确认、数据包路由和加密等。
在Consumer端和Provider端都会有一个RPCRuntime实例,负责双方之间的通信,可靠地将存根船渡地数据包传输到另一端。
RPC调用过程可以分为四个阶段,分别是服务暴露过程、服务发现过程、服务引用过程和方法调用过程。
服务暴露又称服务导出,服务导出的叫法相对于服务暴露更加形象一些。服务暴露发生在Provider端。
根据服务是否暴露到远程可以分为两种,一种是服务只暴露到本地,另一种则是暴露到远程。
Provider端的应用服务信息包括Provider端的地址、端口、应用服务需要暴露的接口定义信息等。Provider 端除了会在应用服务启动的时候将服务信息注册到注册中心,还会与注册中心保持心跳保活如果Provider端某个节点异常下线,注册中心在一段时间的保活检查后,就会将该节点的信息从注册中心中移除,防止Consumer端把请求发送到该下线的节点上。因为业务迭代迅速,服务端的服务变动及上下线很频繁,通过注册中心管理服务的地址信息可以让客户端动态地感知服务变动,并且客户端不需要再显式地配置服务端地址,只要配置注册中心地址即可,而注册中心集群一般不会变动。注册中心的内容会在后续更新介绍。
服务发现的过程发生在(Consumer)端,服务发现的过程也就是寻址的过程,Consumer端如果要发起RPC调用,则需要先知道自己想要调用的应用服务有哪些服务提供者,也就是需要知道这些服务提供者的地址和端口。
服务发现的方式有两种,分别是直连式和注册中心式,对应的是Provider端的两种服务暴露方式。
服务引用的过程发生在服务发现之后,当Consumer端通过服务发现获取所有服务提供者的地址后,通过负载均衡策略选择其中一个服务提供著的节点进行服务引用。服务引用的过程就是与某一个服务节点建立连接,以及在Consumer端创建接口的代理的过程其中建立连接也就是两端的RPCRuntime 建立连接的过程。
当服务引用完成后,Consumer端与Provider端已经建立了连接,可以进行方法的调用。
(1)服务消费者以本地调用方式(即以接口的方式)调用服务,它会将需要调用的方法、参数类型、参数传递给服务消费方的本地存根。
(2)服务消费方的本地存根收到调用后,负责将方法、参数等数据组装成能够进行网络传输的消息体(将消息体对象序列化为二进制数据),并将该消息体传输给RPC通信者。
(3)Consumer 端的RPC通信者通过sockets 将消息发送到Provider端,由Provider端的RPC通信者接收。Provider端将收到的消息传递给服务提供方的本地存根。
(4)服务提供方的本地存根收到消息后将消息对象反序列化。
(5)服务提供方的本地存根根据反序列化的结果解析出服务调用的方法、参数类型、参数等信息,并调用服务提供方的服务。
(6)服务提供方执行对应的方法后,将执行结果返回给服务提供方的本地存根。
(7)服务提供方的本地存根将返回结果序列化,并且打包成可传输的消息体,传递给Provider端的RPC通信者。
(8) Provider端的RPC通信者通过sockets将消息发送到Consumer端,由Consumer端的RPC通信者接收。Consumer端将收到的消息传递给服务消费方的本地存根。
(9)服务消费方的本地存根收到消息后将消息对象反序列化。反序列化出来的是方法执行的结果,并将结果传递给服务消费者。
(10)服务消费者得到最终执行结果。
服务暴露、服务发现、服务引用和方法调用这四个阶段组成了整个RPC的执行过程。
下面举一个例子来将这四个阶段连接起来。
现在有一个订单服务应用,其中订单服务提供了查询订单等方法。现在需要将该订单服务部署在三个节点上,分别是节点A、节点B和节点C。除了订单服务,还有一个用户服务,用户服务内的一个查询订单的功能需要调用订单服务的查询订单方法。所以这里的订单服务就是服务提供方,而用户服务就是服务消费方。订单服务每在一个节点上完成部署后,该节点的信息都会被注册到注册中心。当用户服务启动时,知道该服务依赖订单服务,所以会先从注册中心执行服务发现的过程,发现订单服务有三个节点提供服务,选择其中一个节点后,与该节点建立连接。当用户发起查看订单的请求时,用户服务会向该节点发送需要调用的方法信息,也就是查询订单方法的方法名、参数类型、参数等。等订单服务执行完成后将结果返回给用户服务,这个过程中订单服务与用户服务之间的连接一直保持活跃。当订单服务的该节点下线时,注册中心通知用户服务该节点已下线,当下次用户服务又发起对订单服务的调用时会选择另一个节点建立连接,并且发送调用请求,这就是远程过程调用的全部过程。
参考资料:《深入理解RPC框架原理与实现》 华钟明著.
作者:良知犹存转载授权以及围观:欢迎添加微信公众号:Conscience_Remains总述现在物联网的概念越来越突出,软件云端小米IOT平台、阿里物联网云等等,嵌入式百度手环开源很久了,此外网上关于ESP8266接入网关进行远程控制的源码不计其数。 物联网嵌入式端开发使用中都是各大主流网络模块,其中无线方式通信方式区分的话,主要分为两类:一类是Zigbee、WiFi、蓝牙、Z-wave等短距离通信技术;另一类是LPWAN(low-powerWide-AreaNetwork,低功...
【PConline 应用】现在一说到玩游戏,估计就会想到端坐在电脑前操作着鼠标键盘在游戏世界中横刀立马,或是拿着手柄在大屏幕前与朋友热烈对战,近几年推出的体感设备让游戏的方式变得更加生动立体。体感设备的出现让我们对游戏外设的发展更加有所期盼,那么在未来的一段时间里面,游戏外设还会怎样发展呢?不妨让我们一起来探讨一下未来游戏外设的发展方向。趋势一:虚拟显示设备将成为主流还记得那些画质粗糙的三维建模吗...
在《如何安装Python+selenium环境+Chrome》文章中详细说明了如何安装selenium,但是在没有网络的情况下,我们下载离线selenium安装包,手动执行安装后,可能会出现运行失败的情况。如:我在使用中就遇到了这样的问题。我是自己电脑可以联网,公司电脑不能连外网,而且在自己电脑上已经安装了selenium+Python环境,可以正常使用,同样的方式在公司电脑上安装Pytho...
测试tcp端口的连通性:使用nc命令来测试udp端口的连通性:使用nc命令来测试tcp端口的连通性:
周末下雨,在家扒拉了几篇10年前的论文。我主要是有个疑问,BBR真的是Von Jacobson的idea吗?毕竟论文作者有他的名字,我想知道范雅各布森在BBR里的角色是什么。但我没有找到。不过还是挖出一些有趣的东西。2011年的一篇论文《BufferBloat: What’s Wrong with the Internet?》:https://queue.acm.org/detail.cfm?id=2076798这一篇是一个关于bufferbloat的讨论,我摘录了其中有趣的一些段落。配置大bu
$(function () { //定义打印前事件 var beforePrint = function () { console.log("打印前"); }; //定义打印后事件 var afterPrint = function () { console.log("打印后"); app.post('b...
.Net C# C++: http://www.codeplex.comhttp://www.codersource.net/http://code.msdn.microsoft.com/?tapm=A39S11G05 Other:http://sourceforge.net/http://opensource.org/http://www.codeproject.com/http://www
求生之路2服务器搭建指南个人存档安装服务器安装steamcmd执行以下命令安装l4d2插件使用安装插件工具个人使用插件服务器配置设置管理员启动服务器安装服务器安装steamcmdmkdir ~/steamcmdcd ~/steamcmdwget https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gztar -zxvf steamcmd_linux.tar.gz./steamcmd.sh一般需要安装以下库文
题目链接:http://acm.zzuli.edu.cn/problem.php?id=2485时间限制: 1 Sec 内存限制: 256 MB题目描述众所周知,每个程序员都有一个背包,里边装着笔记本电脑(才不是为了随时改bug呢),耳机,移动电源,switch等。现在,L同学有一个背包,这个背包比较奇特,首先它的空间特别大,其次呢,它装东西要遵循一个规则:装的东西的重量只能递增。毕竟...
Ubuntu 16.04 + ROS Kinetic 学习镜像2017年01月20日 Other 评论 7 条 阅读 6,423 次版权声明:本文为zhangrelay原创文章, 转载请注明,谢谢...转载:http://blog.exbot.net/archives/2972 Ubuntu 16.04 + ROS Kinetic 镜像
想了很久,还是决定养成记录自己学习工作的一些心得。
查看1、查看表空间的名称及大小 select t.tablespace_name, round(sum(bytes/(1024*1024)),0) ts_size from dba_tablespaces t, dba_data_files d where t.tablespace_name = d.tablespace_name group by t.tablespace_name;