RPC架构基本结构和核心技术

当你在构建一个分布式系统时,势必需要考虑的一个问题是:如何实现服务与服务之间高效调用?当然,你可以使用Dubbo或Spring Cloud等分布式服务框架来完成这个目标,这些框架帮助我们封装了技术实现的复杂性。那么,假如没有这些框架,而需要自己来实现远程调用,你应该怎么做的?这就需要引入今天讨论的话题:RPC架构。

RPC架构的基本结构

RPC的英文全称为Remote Procedure Call,也就是远程过程调用。我们通常把发生交互关系的两个服务分别称为服务的提供者(Provider)和消费者(Consumer)。简单来说,RPC就是用来实现服务的消费者向提供者发起远程调用的过程,这是RPC最简单的一种表现形式。


接下来,如果我们把上图做一些展开。如果想要实现服务提供者和消费者之间的有效交互,那么两者之间就需要确立与网络通信相关的网络协议以及通信通道。同时,服务的提供者需要把自己的服务调用入口暴露出来,并时刻准备接收来自消费者的请求。这样,RPC架构就演变成这个样子。


在上图中,我们把通信通道和网络协议分别命名为RpcChannel和RpcProtocol,而把提供者接收请求的组件称为RpcAcceptor,把消费者发起请求的组件称为RpcConnector。

然后,对于服务提供者和消费者而言,为了双方能够正常识别所发送的请求和所接收到的响应结果,需要定义统一的契约。我们把这种契约称为远程API,以与本地API进行区别。基于同一套远程API的定义,RPC架构就具备了根据业务来定义通信契约的能力。

类似的,为了我们更好的区分RPC架构中的角色,我们把真正提供业务服务的组件称为RpcServer,而把发起真实客户端请求的组件称为RpcClient。这样,RpcServer负责实现远程API,而RpcClient负责调用远程API。


当然,对于远程API而言,服务提供者和消费者的处理方式显然是不一样的。提供者需要根据消费者的请求来调用RpcServer的具体实现并返回结果,这部分的工作由RpcInvoker来执行,而消费者通过RpcCaller组件对请求进行编码之后发送到服务方并等待结果。

最后,为了降低开发人员的开发难度,让远程调用的执行过程看上去就先在执行本地方法一样,在主流的RPC实现方法中通常都会在客户端添加代理机制的实现组件RpcProxy,从而提供远程服务本地化访问的入口。另一方面,在服务器端,为了更好地控制业务方法执行过程,通常也会引入具备线程管理、超时控制等机制的RpcProcessor组件。


这样,我们对整个RPC架构的演进过程做了详细的描述。可以看到RPC架构有左右对称的两大部分构成,分别代表了一个远程过程调用的客户端和服务器端组件。客户端组件与职责包括:

  1. RpcClient,负责导入(import)由RpcProxy提供的远程接口的代理实现
  2. RpcProxy,远程接口的代理实现,提供远程服务本地化访问的入口
  3. RpcCaller,负责编码和发送调用请求到服务方并等待结果
  4. RpcConnector,负责维持客户端和服务端连接通道和发送数据到服务端

服务端组件与职责包括:

  1. RpcServer,负责导出(export)远程接口
  2. RpcInvoker,负责调用服务端接口的具体实现并返回结果
  3. RpcAcceptor,负责接收客户方请求并返回请求结果
  4. RpcProcessor,负责在服务方控制调用过程,包括管理调用线程池、超时时间等

而客户端和服务器端所共有的组件包括:

  1. RpcProtocol,负责网络传输协议的编码和解码
  2. RpcChannel,网络数据传输通道

这样,我们对一个典型RPC架构中的基本结构和组件已经都了解了,接下来我们再来重点分析想要实现这个架构中所应该具备的技术体系。

RPC架构的技术体系

从RPC架构的基本结构和组件出发,我们可以进一步梳理想要实现RPC架构的技术体系,包括网络通信、序列化、传输协议和远程调用。

网络通信

首当其中的无疑是网络通信。网络通信涉及面很广,RPC架构中的网络通信关注于网络连接、IO模型和可靠性设计。

基于TCP协议的网络连接有两种基本方式,也就是通常所说的长连接和短连接。长连接和短连接的产生在于客户端和服务器端采取的关闭策略,具体的应用场景采用具体的策略,没有十全十美的选择,只有合适的选择。在RPC框架实现过程中,考虑到性能和服务治理等因素,通常使用长连接进行通信,典型的实现框架就是Dubbo。

关于IO模型,最简单、最基础的就是阻塞式IO(Blocking IO,BIO),BIO要求客户端请求数与服务端线程数一一对应,显然服务端可以创建的线程数会成为系统的瓶颈。因此,在RPC架构中,我们通常都会使用非阻塞IO(Non-blocking IO,NIO)技术来提供性能。

由于存在网络闪断、超时等网络状态相关的不稳定性以及业务系统本身的故障,网络之间的通信必须在发生上述问题时能够快速感知并修复。常见的网络通信保障手段包括链路有效性检测以及断线之后的重连处理等

序列化

想要在网络上传输数据,就需要用到数据序列化技术。序列化的方式有很多,常见的有文本和二进制两大类。XML和JSON是文本类序列化方式的代表,而二进制实现的方案包括Google的Protocol Buffer和Facebook的Thrift等。

性能可能是我们在序列化工具选择过程中最看重的一个指标。性能指标主要包括序列化之后码流大小、序列化/反序列化速度和CPU/内存资源占用。下表中我们列举了目前主流的一些序列化技术:

序列化时间

反序列化时间

大小

压缩后大小

Java 

8654

43787

889

541

hessian

6725

10460

501

313

protocol buffer

2964

1745

239

149

thrift

3177

1949

349

197

json-lib

45788

149741

485

263

jackson

3052

4161

503

271

fastjson

2595

1472

468

251

可以看到在序列化和反序列化时间维度上Alibaba的fastjson具有一定优势,而从空间维度上看,相较其他技术我们可以优先选择Protocol Buffer。

传输协议

在ISO/OSI的7层网络模型中,RPC架构的设计和实现通常会涉及传输层及以上各个层次的相关协议,通常所说的TCP协议就属于传输层,而HTTP协议则位于应用层。传输协议的消息包括消息头和消息体两部分,消息体表示需要传输的业务数据,而消息头用于进行传输控制。图


图7

可以看到每个层次都从上层取得数据,加上消息头信息形成新的数据单元,并将新的数据单元传递给下一层次。

我们可以使用TCP协议和HTTP协议等公共协议作为基本的传输协议构建RPC架构,也可以使用基于HTTP协议的Web Service和RESTful风格设计更加强大和友好的数据传输方式。但大部分RPC框架内部往往使用私有协议进行通信,这样做的主要目的是对共有协议进行精简,从而提升性能。另一方面,出于扩展性的考虑,具备高度定制化的私有协议也比公共协议更加容易实现扩展。这方面典型的示例还是Dubbo框架,它提供了完全自定义的Dubbo协议。

远程调用

RPC本质也是一种服务调用,而服务调用存在两种基本方式,即单向(One Way)模式和请求应答(Request-Response)模式,前者体现为异步操作,而后者一般执行同步操作。

同步调用会造成业务线程阻塞,但开发和管理相对简单。同步调用时序图如下所示,我们可以看到服务线程发送请求到IO线程之后就一直处于等待阶段,直到IO线程完成与网络的读写操作之后被主动唤醒。


使用异步调用的目的在于获取高性能。在实现异步调用过程中,我们通常都会使用到Java中所提供的了Future机制。Future调用可以进一步细分成两种模式,Future-Get模式和Future-Listener模式。Future-Get模式参考下图:


可以看到这种模式下通过主动get结果的方式获取Future结果,而这个get过程是串行的,会造成执行get方法的线程形成阻塞。而Future-Listener模式则不同,在Future-Listener模式中需要创建Listener,当Future结果生成时会唤醒注册到该Future上的Listener对象,从而形成异步回调机制。

除了同步和异步调用之外,还存在并行(Parallel)调用和泛化(Generic)调用等调用方法,虽然也有其特定的应用场景,但对于RPC架构而言并不是主流的调用方式,这里不做具体展开。

可以说,RPC是分布式系统中一项基础设施类的技术体系,但凡涉及到服务与服务之间的交互就需要使用到RPC架构。当你在使用一个分布式框架时,可以尝试使用今天介绍的RPC架构的基本结构和技术体系进行分析,从而加深对这项技术体系的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/361498.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gitlab合并代码并解决冲突演示

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

Jenkins定时构建自动化(二):Jenkins的定时构建

目录 ​编辑 一、 jenkins定时构建语法: 1. 语法规则: 2. 常见用法举例 3. 再次举例 接上一篇:Jenkins定时构建自动化(一):Jenkins下载安装配置:Jenkins定时构建自动化(一):Jenkins下载安装配置-CSDN博客 …

input()函数——输入

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 input()函数可以提示并接收用户的输入,将所有的输入按照字符串进行处理,并返回一个字符串,input()函数的…

化茧成蝶 | 继HuggingFace首家落地大模型具身智能场景

关于具身智能的起源 近年来,大语言模型(LLMs)的兴起给机器人领域带来了革命性的改变,大模型赋予了传统机器人理解和推理的能力,让具身智能这一概念再度出现在大众的视角中。OpenCSG 作为国内 AI 开源社区的先锋&#…

python flask 入门-helloworld

学习视频链接: 01-【前奏】课程介绍_哔哩哔哩_bilibili 1.安装flask pip install flask 踩坑记:本机不要连代理,否则无法install 提示报错valueError: check_hostname requires server_hostname 2.程序编写 在根目录下创建 app.py fr…

从零开始学docker(四)-安装mysql及主从配置(一)

mysql MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关…

【HDC.2024】华为云Astro低代码平台开启AI敏捷组装时代,探索低代码创新无限可能

6月22日,华为开发者大会2024期间,华为云举办了以“敏捷组装时代来临「高低零码智能协同」加速行业创新”为主题的Astro低代码平台专题论坛。论坛汇聚了业界精英和专家学者,共同探讨低代码技术在推动企业数字化转型中的重要实践及未来发展趋势…

cs与msf权限传递,与mimikatz抓取win2012明文密码

CS与MSF的权限互相传递抓取windows2012的明文密码 CS与MSF的权限互相传递 1、启动cs服务端 2、客户端连接 3、配置监听,并设置监听端口为9999 4、生成脚本 5、开启服务,下载并运行木马 已获取权限 6、进入msf并设置监听 7、cs新建监听,与m…

【Linux】UDP协议

目录 传输层端口号netstat端口号范围划分认识知名端口号(Well-Know Port Number) UDP协议UDP协议端格式UDP的特点UDP的缓冲区UDP使用注意事项基于UDP的应用层协议 传输层 通过前面文章对于应用层的讲解,我们知道应用层主要是将我们的数据按照协议的格式进行划分&am…

注册安全分析报告:PingPong

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …

Day15 —— 大语言模型简介

大语言模型简介 大语言模型基本概述什么是大语言模型主要应用领域大语言模型的关键技术大语言模型的应用场景 NLP什么是NLPNLP的主要研究方向word2vecword2vec介绍word2vec的两种模型 全连接神经网络神经网络结构神经网络的激活函数解决神经网络过拟合问题的方法前向传播与反向…

【Linux】锁|死锁|生产者消费者模型

🔥博客主页: 我要成为C领域大神🎥系列专栏:【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 ​ ​ 访问互斥 …

力扣-两数之和

文章目录 题目题解方法1-暴力方法2-哈希 题目 原题链接:两数之和 题解 方法1-暴力 我最先想到的方法就是暴力,两层for循环,也能通过。(拿到算法题在没有思路的时候暴力就是思路,哈哈哈) public class T…

【STM32-存储器映射】

STM32-存储器映射 ■ STM32F1-4G地址空间分成8个块■ STM32F1-Block0■ STM32F1-Block1■ STM32F1-Block2■ STM32F1- ■ STM32F1-4G地址空间分成8个块 ■ STM32F1-Block0 有出厂 BootLoader 就可以使用串口下载程序。如Keil5图中IROM地址是0x8000000 开始 就是flash地址 ■ S…

2-17 基于matlab的改进的遗传算法(IGA)对城市交通信号优化分析

基于matlab的改进的遗传算法(IGA)对城市交通信号优化分析。根据交通流量以及饱和流量,对城市道路交叉口交通信号灯实施合理优化控制,考虑到交通状况的动态变化,及每个交叉口的唯一性。通过实时监测交通流量&#xff0c…

代码随想录-Day41

46. 携带研究材料(第六期模拟笔试) 题目描述 小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实…

GroundingDINO1.5突破开放式物体检测界限:介绍与应用

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

小程序 UI 风格,引人入胜

小程序 UI 风格,引人入胜

如何基于项目人力和管线方案选择FGUI和UGUI

1)如何基于项目人力和管线方案选择FGUI和UGUI 2)TMP字体出包丢失字体描边 3)如何将一张贴图经过Shader处理后的结果输出给另外一个Shader使用 4)为什么我的水这么干净,和UE教程里的有差别 这是第390篇UWA技术知识分享的…

Handling `nil` Values in `NSDictionary` in Objective-C

Handling nil Values in NSDictionary in Objective-C When working with Objective-C, particularly when dealing with data returned from a server, it’s crucial (至关重要的) to handle nil values appropriately (适当地) to prevent unexpected crashes. Here, we ex…