首页天道酬勤Houye的论文解读,Houye的论文

Houye的论文解读,Houye的论文

张世龙 05-13 12:06 129次浏览

论文地址: http://birrell.org/Andrew/papers/implementing RPC.pdf

论文全文翻译连接: https://MP.csdn.net/MP _ blog/creation/editor/11966318

注意:论文是20世纪80年代提出的,仍然有很大的影响,本文根据当时的技术水平进行阐述。

一、论文简介:简化http://www.Sina.com/http://www.Sina.com /分布式计算,构建远程呼叫类似本地呼叫。

3358www.Sina.com/如何处理服务器故障或通信故障将远程调用集成到现有系统中时数据传输和相应协议的设计如何保证数据的完整性和安全性3、论文目标3358www.Sina.com/

希望33558www.Sina.com/RPC简化远程呼叫,并体验类似本地呼叫的体验,而不考虑通信问题。

1、论文核心:

高效通信,含义强烈简洁。 通信安全-完整的端到端通信http://www.Sina.com/http://www.Sina.com/user (客户端) user-stub (客户端存根) RPC运行时) rre

图1

2、调用流程如图1所示,user、user-stub、RPCRun-time的实例在调用方的机器上运行。 在调用server、server-stub和另一个RPCRuntime实例的计算机上运行。

如果用户希望远程调用,则实际调用的本地user-stub的相应代码。 user-stub将调用的规范和参数打包成一个或多个包,并通过RPC运行时(RPC通信包)将其传输到调用计算机。

2、论文内容简介:服务端接收到这些分组后,相应的RPC运行时(RPC通信分组)将它们传递到server-stub。 然后,服务器- stub对它们进行解包,并调用相应的本地实现。 同时,客户端调用进程锁定,等待服务端返回的结果包。 服务端调用完成后,返回server-stub,结果返回客户端相应的RPC运行时(RPC通信包)挂起的进程。 然后,用user-stub解除包,最后返回给用户。

将客户端和服务端代码放在一台计算机上,直接绑定在一起,这样程序就可以运行,而无需使用user-stub和server-stub。 问题: RPC是如何确定是本地呼叫还是交叉服务呼叫的? )

RPC运行时(RPC通信包)是Cedar系统的标准部分,因此程序员不需要编写与通信相关的代码,但user-stub和server-stub是由名为Lupine的程序自动生成的

注:当前的开源框架,例如RPCRuntime和stub (如dubbo )由框架本身提供。

三、详细实现论述

1、绑定

绑定概念类似于今天的注册中心,如zookeeper、控制台、nacos和etcd

绑定解决的问题:

绑定机制的客户端如何指定他想绑定到那台机器? 被调用方如何确定被调用方的计算机地址,并指定要在被调用方调用的过程? 第一个是如何明确定义被调用的机器,第二个是在明确定义之后,如何确定被调用机器的地址,改变地址上的对应进程

1.1、对接口命名RPC包提供的绑定操作是将接口的接口绑定到接口的导出器。 绑定后,调用导入实现远程导出器兼容接口。

接口的名称由两部分组成:类型和实例。

定义类型的目的是在抽象级别指定调用方希望提供程序实现哪个接口。 实例用于指定启用接口的实现。

接口名称的语义未在RPC包中指定。 ——这些是接口引用者和接口提供程序之间的协议,并不是完全强制在RPC包中执行。 然而,RPC分组确定服务提供商使用接口名称定位具体位置的方式。

1.2、查询相应的导出接口Grapevine分布式数据库进行RPC绑定。 Grapevine数据库是分布式的,每个库至少有三个副本,本身非常可靠。

实现绑定方案的探索:

方案1 )写下与发布的接口包直接对应的服务提供者的网络地址。 缺点:不太灵活,是硬编码的。

方案2 )使用某个广播协议确定服务提供商。 缺点)由于不通知用于处理广播和不在同一LAN上的服务,干扰不具有该接口的其他服务。

利用方案Grapevine分布式数据库完成绑定,服务消费者和服务提供者与数据库进行交互,解决了上述方案1、方案2的问题。

格拉皮埃v

ine数据库如何存储服务提供者的数据呢?类似下面这种方式:

组类型结构:列表<接口,接口的实例>个体类型接口:列表<接口的实例,实例所在机器的网络地址>

     当服务端导出接口(发布接口)的时候,调用链为server-->server-stub-->RPCRuntime中的exportinterface,然后将接口类型、实例和分发器传入exportinterface,最后将数据保存到数据库,如果数据存在则更新。表包含以下数据:接口名称、实例、32位的唯一标识(用于客户端调用时验证)

      当时客户端希望绑定到服务提供者时,调用链为user-->user-stub-->RPCRuntime中的importinterface,然后将接口类型、实例传入importinterface,RPCRuntime查询Grapevine数据库中改接口实例的网络地址。

     然后客户端拿着从Grapevine数据库查询出来的网络地址发起请求,如果被请求的机器上没有对应的接口实现,则绑定失败。也可以用接口进行绑定,这样更灵活,每次绑定的时候动态查询存在的实例。不一定使用Grapevine数据库,也可以使用其它能达成类似功能的方法。

2、传输协议设计 2.1必要设计

目标:减少调用耗时

方案一:使用当时的Grapevine协议,缺点:性能不太高

方案二:设一个个专用用于RPC的传,优点:相对于Grapevine协议,性能能增长10倍以上

如果传输的数据量特别大,传输耗时很长,使用建立和关闭连接(短链接)可以接受,因为建立和关闭连接的开销远小于传输的开销。相反,对RPC来说连接的客户端特别多,频繁的建立和销毁连接,就不太适合了(建议使用长连接)。

如果调用过程出现异常,服务端应该立刻终止,并将异常信息返回给调用方。该异常有可能是网络问题,也有可能是服务器崩溃,用户并不知道是哪一种异常(笔者觉得应该能做到异常的区分),如果服务端代码死循环了,服务端会一直运行,并且不会报告异常,这与调用本地死循环是同样的道理。

调用时将调用标识符、参数、要调用的接口信息传递给服务提供端,服务端解析收到的数据,调用对应的方法,将结果返回给调用者。

发送端赋值重传数据包,知道收到接口端的确认消息,服务端和客户端都可能是发送端(服务端在发送结果的时候,角色就是发送端,客户端在请求服务的时候,角色同样是发送端)。

调用标识符有两个用途:

1、对调用端来说可以区分不同的请求

2、对被调用端来说,可以用它过滤重复的请求

活动的组成:调用机器标识符 + 进程相对标识符 + 序列号

序列号只能是单向的,比如递增,但是不要求连续。(类似数学上的单调非连续函数)

因为活动和进程相关,被调用的机RPCRuntime维护一个表,表里给出每个活动最后一次的调用序列号。在服务端接受到调用时,查询对应的序列号,看看对应的序列号是否大于表中的序列号,如果小于可以丢弃此请求。发生重传的话,也可以做对应的过滤。

如果小于的话,说明发生了重复调用,可以丢弃。因为相同的调用每次都会增加序列号的值。(笔者这里理解:‘机器标识符+进程相对标识符’  标识一个请求,后面的‘序列号’标识同一个请求发送了多少次)

  2.2 调用过程

数据包的发送方负责重新发送未被接收端确认的数据,如果调用时间非常长,调用者就会定期发送探测包,被调用这对其进行确认。好处是在服务端奔溃或者通信故障时,调用方能得到通知,发送的频率随着时间的增加,发送频率越来越低,直到每5分钟发送一次探测包。如果探测包一直没有收到响应,调用方就会认为通信存在问题,可以做一些对应的处理。

如果发送方发送的数据包太大,会被拆成多个数据包发送,除了最后一个数据包之外,前面的数据包都需要被调用方明确的确认。调用方和被调用方都只是用一个包缓冲区,为了消除重复的包,每一个被发送包都有对应的序列号。如下图:

user发起的一个调用由于数据太大被拆成了2个包,假设拆分后的数据包分别为A包和B包,发送A包的时候server端接收到了,给user返回一个收到A包的确认消息。然后发送B包,server接收到B包,但是某些原因server没有向user发送B包的确认消息。由于server2个包都接受到了,然后将A、B两个包组合还原,解析出参数后执行处理,此时user端觉得是不是server没有收到,于是重传B个包,此时server收到了重复B包,内部查询了一下,发现之前已经收到这个包了。于是直接向user端返回一个B包的确认消息,此时server端已开启的处理流程也在继续。user端收到B包的确认消息后,进入等待状态(同时也会在等待的过程出发送探测包,以确保两者之间的通信网络正常)。等服务端处理完成后,想user端发送结果包。user端收到结果包后没有向server返回收到结果的确认消息。于是server端重传结果包,user端返回收到结果的包的确认消息,到此调用结束。

2.3异常的处理

异常包括服务端的异常、Rpc框架本身的异常,需要将这些异常信息返回给调用端

2.4安全

完编写中...

rpc系统,grpc protobuf rpc底层原理,rpc协议详解