java中rpc,java rps

文首,思考一个问题:为什么需要 RPC 服务?在传统的开发模式中,我们通常将系统的各个服务部署在单台机器,随着服务的扩展,这种方式已经完全无法满足系统大规模的扩

考虑一下文章开头的问题:“为什么我们需要RPC 服务?”

83153e315d264f358d708e9275553f9c~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=y5G9bndTFyQ0%2BsB1rP%2BawbYjUjs%3D

传统的开发模式通常是将各个系统服务部署在单机上,但这种方式已经无法支持大规模系统扩展的需求。由此,分布式系统诞生了。在分布式系统中,系统最重要的部分就是各个服务之间的RPC调用。

RPC 的正式名称是远程过程调用——。它是一种在不了解底层网络技术的情况下通过网络向远程计算机程序请求服务的方法。简单点就是通过一定的协议和方法调用远程计算机上的服务和调用本地服务是一样的。

总的来说,实现RPC的好处是可以基于通用的HTTP协议,也可以在TCP之上封装自定义的协议。 HTTP协议具有出色的跨平台特性,特别适合拥有许多不同系统的企业。然而,由于HTTP头较长且性能较差,基于TCP协议的RPC可以以明显的速度建立长连接。虽然高效,但是非常困难和复杂。

RPC的诞生使得构建分布式应用变得更加容易,并且大大扩展了系统的可扩展性和容错能力。这为业务逻辑复杂的系统进行面向服务的改造和高可用升级提供了潜力。

RPC 调用分类

对RPC 调用进行分类的方法有很多种。

从通信协议层面,可以分为以下几类。

基于HTTP协议的RPC。

基于二进制协议的RPC。

基于TCP协议的RPC。

可以分为是否跨平台。

单语言RPC,例如RMI、远程处理。

跨平台RPC,例如Google Protobuffer、Restful JSON 和http XML。

从调用过程来看,可以分为同步通信RPC和异步通信RPC。

同步RPC:是指客户端发起调用,然后必须等待调用完成并返回结果。

异步RPC:指客户端不关心调用后返回的执行结果。如果客户端需要结果,可以通过提供异步回调来检索返回的信息。大多数RPC 框架都支持这两种调用方法。

RPC 框架结构

完整的RPC框架的主要模块如图所示。

8d82497a271045529d763ffcc49b3716~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=wt4CZkV70TWyylnGL2qHScy%2BSmE%3D

RPC 服务器的主要作用是提供客户端可以调用和访问的服务。服务端通过接收者接收客户端的调用请求,根据相应的RPC协议进行解码,获取调用时的调用方法及相关参数。完成后,通过服务器后台处理模块完成处理,并将结果返回给客户端。

服务调用对客户端来说是完全透明的,调用远程方法就像调用本地服务一样,通过远程连接与服务器建立通道,并通过相应的协议对服务进行编码。被调用的方法和相关参数被发送到服务提供者。

开始

RPC 模块详解

现在,根据上面的RPC架构图,我们来分解图中的各个模块,并解释一下每个模块的作用。

Server:RPC服务的提供者,负责导出RPC服务。

客户端:RPC服务的消费者,负责调用RPC服务。

代理:通过动态代理为远程接口提供代理实现。

执行者(调用者):对于客户端来说:主要负责编码服务调用、发送调用请求、等待结果返回。对于服务器端:负责处理调用逻辑并返回调用结果。

协议管理(Protocol):协议管理组件,负责整个RPC通信协议的编码/解码。

Connector:负责维护客户端和服务器之间的长连接通道。

后台处理(处理器):负责管理和调度整个调用服务,包括线程池、分发、异常处理等。

连接通道:客户端和服务器之间的数据传输通道。

具体到JAVA平台,这3、4一般是使用动态代理实现的,而5、6、7、8则使用NIO或者一些高性能的NIO框架(如mina或者netty)来实现:

最简单的 RPC JAVA 实现

进一步分解组件、划分职责后,我们以最简单的Java RPC框架实现为例,分析RPC的具体逻辑。

RPC框架服务暴露代码:

a0fca272c29a4c3fa1be634b585b6574~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=a1Pv3z4BKruyR7To63etQsii2GM%3D

在服务器端公开服务的代码首先检查传入的端口和服务是否合法,然后,为了简单起见,我们在这里不使用NIO 方法。直接使用Java序列化方法,通过反射传入传入的数据,检索被调用的方法和参数,在本地执行,结果通过socket返回给客户端。

RPC框架服务调用代码:

5a5a9cc7e33e4d8485ef6c7741175ca4~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=%2BwoB6zmWyF%2B0SqgvyDfSoA9DRCc%3D

框架内客户端调用的代码首先检查对应的端口和主机是否合法,然后用代理对象上的方法拦截调用,并传递方法和方法。带参数远程执行并检索远程执行返回的结果。

RPC调用测试:

f97cf26614c34038ad30327366c9ce02~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=7kbS6QOSQZb9ulDk%2Bbk0rKGAwXA%3D

52f6adb6065a4a1196470ea3c3497498~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=NcUKYOa0TnbgfCAL5yefppMEPho%3D

aad9a374ce744f9dbbc39bf98dd1e7a8~noop.image?_iz=58558&from=article.pc_detail&lk3s=953192f4&x-expires=1717815021&x-signature=DdPjdViDeBzqzD%2B%2FXXWetJ%2FxpgQ%3D

如上图所示,服务端暴露了一个接口服务HelloService,客户端通过RPC调用成功。

想法

自定义 RPC 协议

协议头

上面的示例程序只完成了一个基本的远程调用,并没有实现RPC框架中的很多组件功能。从最简单的代码版本我们可以看出,发起RPC调用最基本的数据是:

接口方法:包含接口的名称和对应的方法名称。

方法参数:包含参数的类型和值。

连接参数包括调用接口版本、接口超时时间等。

因此,如果要自定义协议来实现RPC,就必须在协议的消息体中包含这部分数据。此外,还必须定义协议元数据。这些元数据通常包括协议标头和协议主体,其中包括所需的参数。该问题包含自定义消息。

元数据通常包括以下字段,其中大多数仅需要1 或2 位。

magic: 幻数,对于解码协议很有用

header_size: 协议标头大小。它很容易解码,也可以用来处理TCP粘性问题。

id : 消息ID。用于识别本次调用。

version: 接口版本

type: 消息类型。包含常规呼叫消息、心跳和控制消息。

status: 消息状态(首次处理或已处理)

body_size: 消息体长度

Serialize_type: 消息体序列化类型

正文:具体消息

具体消息

对于通过网络发送的数据,这种编码过程显然意味着序列化大小越小,传输速度越快,只要信息能够足够好地解码即可。开销越低,效率就越高。目前JAVA平台上常用的序列化方式有xml、json、binary(包括thrift、hession、kryo等)。

我们建议使用二进制模式通过RPC 调用进行序列化。在大多数测试中,二进制模式序列化表现良好。另外一个有趣的事情是,随着JDK 版本的每次升级,JAVA 自身的序列化方法变得更加高效。

服务端调用优化

前面的示例代码只是简单地考虑了组件内服务器和客户端的实现;一个完整的RPC框架需要考虑每个调用的实现和优化。同时还需要高可靠性和容错能力来满足业务需求。

具体来说,动态代理模块没有使用Java自带的动态接口,但是连接通道和连接模块使用了更好的第三方NIO。作为netty 来实现这一点,后端处理模块需要考虑的不仅仅是执行和返回结果。

并发控制:同时处理多个请求时如何管理和控制线程池和超时延迟。

版本分离:当服务存在多个版本时,如何保证不同的调用者能够调用正确的服务。

服务路由:当服务提供商拥有多台机器时,如何改进系统负载平衡并路由到正确的服务器。

服务降级:如果多个服务重要性不一,在保证核心业务稳定的情况下,可以适当降低非核心业务的优先级。

业务监控和报警:当业务发生异常时,运维和相应的系统负责人可以第一时间获取报警和错误信息。

上述考虑大部分必须结合运维层面来考虑,但RPC框架本身也必须提供足够的支持,以保证足够的健壮性。

需要注意的一些地方

RPC 有很多优点可以使用,但是如果您真的想成为面向服务的,还有很多事情需要考虑。

网络问题:您无需担心是否可以拨打本地电话。各种外部网络环境、端口阻塞、IP 限制等都可能导致网络调用无法成功完成。因此,RPC服务器通常需要考虑幂等性和容错性,并且其接口需要强大且健壮的设计。

异常处理:RPC服务与本地服务最大的区别在于RPC服务存在分布式一致性问题。如果服务未成功调用,本地和远程服务可能会处于不一致的状态。如何处理异常和回滚机制。此外,确保强一致性和最终一致性的需求通常取决于特定的业务需求,并且必须加以考虑。

由于网络原因,本地服务处理RPC 服务的速度通常要慢一个数量级。如果您的业务比较轻量级或者并发量较低,那么实现RPC服务后,甚至可能不需要进行系统调试。在线问题分析可能非常复杂,因此实施它的决定需要权衡相关的优点和缺点。

文末小结

本文简单介绍了RPC的基础知识以及相关分析,供大家参考。要了解更多信息,请查看一些最主流的RPC 框架,例如dubbo、protobuff 和thrift。 – 详细调查源代码。很浅。

原创文章,作者:小条,如若转载,请注明出处:https://www.sudun.com/ask/85074.html

(0)
小条的头像小条
上一篇 2024年6月1日
下一篇 2024年6月1日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注