广昌资讯网
日期归档
当前位置:主页>国际新闻>
整天跟微服务打交道,你不会连RPC都不知道吧?
来源:iamfortuju.com  阅读量:1545

首先要了解所谓的RPC,为什么RPC,RPC指的是远程过程调用,即两个服务器A,B,一个部署在A服务器上的应用程序,想要调用B服务器上应用程序提供的函数/方法,因为它不是一个无法直接调用的内存空间。它需要表达呼叫的语义,并通过网络传递呼叫数据。

7564501-0651f3aa4a92436d

RPC功能目标

RPC的主要功能目标是在提供强大的远程调用功能时,更轻松地构建分布式计算(应用程序),而不会损害本地调用的语义简单性。为了实现这一目标,RPC框架需要提供透明的调用机制,不需要用户明确区分本地调用和远程调用。基于存根结构的实现结构在《浅出篇》中给出。下面我们将具体细化存根结构的实现。

RPC调用分类

有两种类型的RPC调用:

7564501-3267a90396cd91df

异步和同步之间的区别在于是否等待服务器执行并返回结果。

RPC结构反汇编

《浅出篇》给出了一个相对粗粒度的RPC实现概念结构,这里我们进一步细化它应该包含哪些组件,如下所示。

7564501-41be9bd2aca8d8fd

RPC服务器通过RpcServer导出远程接口方法,客户端使用RpcClient导入远程接口方法。客户端像本机方法一样调用远程接口方法。 RPC框架提供接口的代理实现,实际调用委托给代理RpcProxy。代理封装了调用信息,并将调用转发给RpcInvoker以进行实际执行。客户端的RpcInvoker通过连接器RpcConnector维护与服务器的通道RpcChannel,并使用RpcProtocol执行协议编码(编码)并通过通道将编码的请求消息发送给服务方。

RPC服务器接收器RpcAcceptor接收客户端的呼叫请求,并使用RpcProtocol执行协议解码(解码)。解码的呼叫信息被传递到RpcProcessor以控制呼叫过程的处理,最后呼叫被调用到RpcInvoker以实际执行并返回呼叫结果。

RPC组件职责

在上面,我们进一步反汇编RPC实现结构的组件。下面我们解释每个组件的职责划分。

7564501-801abe546a29195f

RPC实施分析

在进一步分解组件并划分职责之后,这里是在Java平台上实现RPC框架概念模型并分析实现中需要考虑的因素的示例。

导出远程接口

导出远程接口意味着只能远程调用导出的接口,而未导出的接口则不能。用于在java中导出接口的代码片段可能如下所示:

7564501-3faf31fe4ba55ba4

我们可以导出整个界面,或者我们可以以更精细的方式导出界面中的一些方法,例如:

7564501-1ecc83a5ba2e6387

在java中有一个特殊的调用是多态的,也就是说,一个接口可能有多个实现,所以在进行远程调用时会调用哪一个?这个本地调用的语义是通过jvm提供的引用多态隐式实现的,因此不能为RPC隐式实现跨进程调用。如果先前的DemoService接口有2个实现,则需要在导出接口时标记不同的实现,例如:

7564501-4dc504c20e1968f0

上面的demo2是另一个实现,我们将它标记为'demo2'来导出,然后远程调用也需要传递标记来调用正确的实现类,从而解决了多态调用的语义。

导入远程接口和客户端代理

导入相对于导出的远程接口,客户端代码必须获取远程接口的方法或过程定义才能启动呼叫。目前,大多数跨语言平台RPC框架使用代码生成器根据IDL定义生成存根代码。这样,实际的导入过程由代码生成器在编译时完成。我使用RPC框架的一些跨语言平台,如CORBAR,WebService,ICE和Thrift都是这样的方法。

生成代码的方式是跨语言平台RPC框架的必然选择,而同一语言平台的RPC可以通过共享接口定义实现。用于在java中导入接口的代码片段可能如下所示:

7564501-a2dc4c1bfb19ee06

在java中,'import'是一个关键字,因此在我们使用的代码片段中引用表达导入接口的含义。这里的import方法也是一种代码生成技术,它只在运行时生成,比静态编译时的代码生成更简洁。 java中提供了至少两种技术来提供动态代码生成,一种是jdk动态代理,另一种是字节码生成。动态代理比字节码生成更方便,但动态代理模式在性能方面不如直接字节码生成,而字节码生成在代码中的可读性要低得多。这两者是一起称重的,并且个人认为牺牲一些性能以获得代码可读性和可维护性更为重要。

协议编解码器

客户端代理需要在发起呼叫之前对呼叫信息进行编码。有必要考虑需要编码哪些信息以及以什么格式传输到服务器以便服务器完成呼叫。出于效率原因,编码越少越好(传输的数据越少),编码规则越简单(执行效率高)。我们先来看一下需要编码的信息:

7564501-b20808a55931e88d

除了上述必要的呼叫信息之外,我们可能还需要一些元信息来促进程序编解码器和未来可能的扩展。通过这种方式,我们的编码消息分为两部分,一部分是元信息,另一部分是呼叫的必要信息。如果设计了RPC协议消息,我们将它放在协议头中的元信息和必要的信息放在协议消息体中。概念RPC协议消息设计格式如下:

7564501-8fae9f6dccfff824

7564501-4c5db85859eded8b

确定格式后,编解码器很简单。因为标头长度是确定的,所以我们更关心消息体的序列化。序列化我们关心三个方面:

1.序列化和反序列化的效率尽可能快。

2.序列化后字节的长度尽可能小。

3.序列化和反序列化兼容性。如果接口参数对象添加了字段,则它是兼容的。

这三点有时与鱼和熊掌不相容。这与具体的序列化库实现细节有关,本文不再进一步分析。

传输服务

协议编码后,将编码的RPC请求消息传输给服务方是很自然的,并且服务方在执行后向客户端返回结果消息或确认消息。 消息的唯一ID,因此重用连接更容易。

由于使用了长连接,第一个问题是客户端和服务器之间需要多少个根连接?实际上,单连接和多连接的使用没有区别。对于具有少量数据传输的应用类型,单个连接基本上就足够了。单连接和多连接之间的最大区别是每个连接都有自己的专用发送和接收缓冲区,因此在不同连接缓冲区中传输的大量数据将获得更好的吞吐效率。因此,如果您的数据传输量不足以使单连接缓冲区保持饱和,那么使用多个连接不会导致任何显着的改进,但会增加连接管理的开销。

连接由客户端启动和维护。如果客户端和服务器直接连接,则通常不会中断连接(物理链路故障除外)。如果客户端和服务器连接到某个负载中继设备,则当连接处于非活动状态一段时间时,这些中间设备可能会中断它。为了保持连接,必须定期发送每个连接的心跳数据,以保持连接不中断。心跳消息是RPC框架库使用的内部消息。在先前的协议头结构中,还有一个特殊的心跳位,用于标记心跳消息,该消息对业务应用程序是透明的。

执行电话

客户端存根所做的只是编码消息并将其传递给服务方,实际的调用过程发生在服务方。服务器存根从以前的结构反汇编中,我们细分了RpcProcessor和RpcInvoker组件,一个负责控制调用进程,一个负责实际调用。在这里我们仍然使用java来实现这两个组件作为例子来分析他们需要做什么?

目前通过反射调用在java中实现代码的动态接口调用。除了本机jdk自己的反射之外,一些第三方库还提供性能更好的反射调用,因此RpcInvoker封装了反射调用的实现细节。

在调用过程的控制中需要考虑哪些因素,以及RpcProcessor需要提供什么样的呼叫控制服务?以下是一些值得启发的观点:

7564501-8a1d8e3d500ad89f

RPC异常处理

无论RPC如何努力使远程调用伪装成本地调用,它们仍然存在很多差异,并且在本地调用时会遇到一些从未遇到的异常。在我们说异常处理之前,让我们比较一下本地调用和RPC调用之间的一些区别:

1.将执行本地呼叫,并且不需要远程呼叫。出于网络原因,可能不会将呼叫消息发送给服务方。

2.本地调用只会抛出接口声明的异常,当RPC框架运行时,远程调用也将耗尽其他异常。

3.本地和远程呼叫的性能可以有很大不同,具体取决于RPC固有消耗的比例。

使用RPC时,这些差异会引起更多考虑。当调用远程接口以引发异常时,异常可能是业务异常,或者它可能是RPC框架抛出的运行时异常(例如网络中断等)。业务异常表示服务方已执行了呼叫,并且由于某些原因可能无法正确执行。但是,RPC运行时异常可能导致服务方根本不执行。调用者的异常处理策略自然需要区分。

由于RPC的固有消耗比本地调用高几个数量级,因此本地调用的固有消耗是纳秒,而RPC的固有消耗是以毫秒为单位。然后,对于过于轻量级的计算任务,导出远程接口以供独立进程服务是不合适的。只有在计算任务上花费的时间远远高于RPC的固有消耗时,才有必要导出到远程接口。

总结

到目前为止,我们已经提出了RPC实现的概念框架,并详细分析了需要考虑的一些实现细节。无论RPC被隐藏,只有深入了解RPC的本质才能更好地应用。

最后,分享一本采访书[Java核心知识点整理]涵盖JVM,锁定,高并发,反射,Spring原理,微服务,Zookeeper,数据库,数据结构等“,以及Java208面试问题(带答案)加入我的粉丝团(Java Fill Road :)免费获得它!掌握这些知识点,你可以在面试中赢得很多候选人,暴击9999分。机会留给准备人员,只有充分的准备,可以让自己在候选人中脱颖而出。

友情链接:
广昌资讯网 版权所有© www.iamfortuju.com 技术支持:广昌资讯网 | 网站地图