手动实现简易版RPC(一)

手动实现简易版RPC(一)

前言

什么是RPC?它的原理是什么?它有什么特点?如果让你实现一个RPC框架,你会如何是实现?带着这些问题,开始今天的学习。

本文主要介绍RPC概述以及一些关于RPC的知识,为后面实现做充足的准备。


1. RPC简述

1.1 什么是RPC

专业定义: RPC是远程过程调用(Remote Procedure Call)。 RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制,让使用者不必显式的区分本地调用和远程调用。

举个🌰:

假设你住在一个大社区里,社区里有很多居民,每个人都有自己的专长。比如,有的擅长修理电器,有的擅长烹饪美食,还有的擅长园艺。有一天,你突然发现家里的水龙头坏了,你并不会修理,于是你想到社区里那位擅长修理电器的居民。

在这个场景下,你可以将自己想象成客户端(Client),那位擅长修理的居民则是服务端(Server)。你想要调用服务端的“修理水龙头”这个“方法”。但是,你和服务端并不在同一个地方,不能直接交流,于是你需要通过一些方式(比如电话,发短信,或者社区的信息平台)来发起这个调用请求。

而达成的效果呢:就像你自己修理水龙头一样的丝滑,你不需要知道整个修理的过程,你只需要知道,修理好了这个结果就行

1.2 为什么要用RPC

回到 RPC 的概念,RPC 允许一个程序(称为服务消费者)像调用自己程序的方法一样,调用另一个程序(称为服务提供者)的接口,而不需要了解数据的传输处理过程、底层网络通信的细节等。这些都会由 RPC 框架帮你完成,使得开发者可以轻松调用远程服务,快速开发分布式系统。

举个🌰:

现在有项目A和项目B两个单独的项目,项目A提供一系列的关于宠物的服务,然后项目B也想使用项目A 的一些服务,完成宠物信息的查询。

项目A的查询猫咪信息的服务接口伪代码如下:

interface CatService {
    /***
     * 获取猫咪信息
     * @return
     */
    Cat getCat(参数1,参数2...);


    /***
     * 按照id获取猫咪信息
     * @param id
     * @return
     */
    Cat getCatById(int id);
    
    //....other
}

如果没有RPC,项目B会如何调用项目A的服务呢?

首先,由于项目A和项目 B都是独立的系统,不能像 SDK一样作为依赖包引入。

那么就需要项目 A提供 web 服务,并且编写一个点餐接口暴露服务,比如访问http:localhost:8088/api/cat 就能调用服务A的猫咪查询服务;然后项目B作为服务消费者,需要自己构造请求,并通过 HttpClient 请求上述地址,拿到相关信息。

如果项目B需要调用更多第三方服务,每个服务和方法的调用都编写一个 HTTP 请求,那么会非常麻烦

示例伪代码如下:

url="http:localhost:8088/api/cat"
req=new Req(参数1,参数2,参数3)
res=httpClient.post(url).body(reg).execute()
cat =res.data

那么如果使用RPC框架,对于项目B来说,要实现上述调用,可能只需要一行代码

cat=CatService.getCat(参数1,参数2,参数3)

看起来是不是和调用自己的方法一样,十分简洁。

2.RPC设计实现思路

基本设计

RPC框架为什么能够简化调用?该如何实现一个RPC框架呢?带着这两个问题,一起往下看

首先呢,我们将上述服务A抽象为服务提供者(producer),服务B抽象为服务消费者(consumer)

请添加图片描述

消费者想要调用提供者,就需要提供者启动一个 web 服务 ,然后通过 请求客户端 发送 HTTP 或者其他协议的请求来调用。
比如请求 http:localhost:8088/api/cat 地址后,提供者会调用 CatService的 getCat方法:

请添加图片描述

但如果提供者提供了多个服务和方法,每个接口和方法是不是都要单独写一个接口?消费者需不需要针对每个接口写一段 HTTP 调用的逻辑么?

其实可以提供一个统一的服务调用接口,通过请求处理器,根据客户端的请求参数来进行不同的处理、调用不同的服务和方法。

可以在服务提供者程序维护一个本地服务注册器,记录服务和对应实现类的映射。

举个🌰:

消费者要调用 CatService服务的 getCat 方法,可以发送请求,参数为 service=CatService,method=getCat 然后请求处理器会根据 service 从服务注册器中找到对应的服务实现类,并且通过 Java 的反射机制调用 method 指定的方法。

请添加图片描述

但是在数据传输过程中是不支持java实体类进行传输的,所以为了达成网络传输,需要对传输的参数等实现序列化和反序列化

请添加图片描述

为了简化消费者发请求的代码,实现类似本地调用的体验。可以基于代理模式,为消费者要调用的接口生成一个代理对象,由代理对象完成请求和响应的过程。所谓代理,就是有人帮你做一些事情,不用自己操心。
至此,一个最简易的 RPC 框架架构图诞生了,下图中的虚线部分:

请添加图片描述

整个简单的调用过程客以参考下图

请添加图片描述

拓展设计

虽然上述设计已经跑通了基本调用流程,但离一个完备的 RPC 框架还有很大的差距,让我们带着问题来进一步完善一下架构设计。

1、服务注册发现
问题 1:消费者如何知道提供者的调用地址呢?

继续我们上述的第一个例子,社区中有人会修理水龙头,那么要想让他帮你来修,你们双方得知道双方的地址,而这个地址,是不是由物业进行保管。因此,我们需要一个 注册中心,来保存服务提供者的地址。消费者要调用服务时,只需从注册中心获取对应服务的提供者地址即可。

架构图如下:

请添加图片描述

主流的注册中心组件:Redis、Zookeeper、Consul、Etcd。Dubbo采用的是ZooKeeper提供服务注册与发现功能。

2、负载均衡
问题 2:如果有多个服务提供者,消费者应该调用哪个服务提供者呢?

我们可以给服务调用方增加负载均衝能力,通过指定不同的算法来决定调用哪一个服务提供者,比如轮询、随机、根据性能动态调用等,在高并发的场景下,需要多个节点或集群来提升整体吞吐能力。。
架构图如下:

请添加图片描述

3、容错机制
问题 3:如果服务调用失败,应该如何处理呢?

为了保证分布式系统的高可用,我们通常会给服务的调用增加一定的容错机制,比如失败重试、降级调用其他接口等等。
架构图如下:

请添加图片描述

4、其他

除了上面几个经典设计外,如果想要做一个优秀的 RPC 框架,还要考虑很多问题。

比如:

  • 服务提供者下线了怎么办?需要一个失效节点剔除机制。
  • 服务消费者每次都从注册中心拉取信息,性能会不会很差?可以使用缓存来优化性能。
  • 如何优化 RPC 框架的传输通讯性能?比如选择合适的网络框架、自定义协议头、节约传输体积等
  • 如何让整个框架更利于扩展?比如使用 Java 的 SPI 机制、配置化等等。

所以,完成 RPC 项目并不难,但做一个完美的 RPC 项目却是难于上青天啊!

总结一下,我们可以通过做一个 RPC 项目学习到网络、序列化、代理、服务注册发现、负载均衡、容错、可扩展设计等知识,相信完成后会收获满满。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全指南:安全访问 Facebook 的技巧

在当今数字化时代,网络安全问题越来越受到人们的关注。尤其是在社交媒体平台上,如 Facebook 这样的巨头,用户的个人信息和隐私更容易受到威胁。为了保护自己的在线安全,我们需要采取一些措施来确保在使用 Facebook 时能够安全可靠…

GET与POST:详述HTTP两大请求方法的语义、数据处理机制、安全特性与适用场景

GET和POST方法在HTTP请求中具有明确的角色分工和特性差异。GET适用于读取操作和不敏感数据的传递,强调可缓存性和安全性,而POST适用于写入操作和敏感数据的提交,提供了更大的数据承载能力和更强的隐私保护。本文详细介绍了GET与POST请求方法的…

利用Sentinel解决雪崩问题(二)隔离和降级

前言: 虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了,不管是线程隔离还是熔断降级,都是对客户端(调…

实战篇05:更新用户基本信息

实战篇05:更新用户基本信息 一、接口信息 1.1 基本信息 请求路径:/user/update 请求方式:PUT 接口描述:该接口用于更新已登录用户的基本信息(除头像和密码) 1.2 请求参数 请求参数格式:application/json 请求参数说…

2024 年 3 月公链行业研报:比特币创新高、Meme 掀热潮、AI 板块露头角

作者:stellafootprint.network 数据来源:Footprint Analytics 公链研究页面 3 月份,加密市场表现强劲,比特币再创历史新高。以太坊价格稳步攀升,而坎昆升级则显著降低了交易成本。Solana 链上 Meme 热潮席卷而来&am…

nandgame中的Memory(内存操作):栈、堆、静态区

Push Memory Push Memory 将内存中的值push到栈内堆栈顶部的值是一个内存地址。从堆栈中弹出地址。获取内存地址的当前内容,并将其推送到堆栈上。POP_A //堆栈顶部的值是一个内存地址。从堆栈中弹出地址。 D *A //获取内存地址的当前内容 PUSH_D //将其推送到…

拉普拉斯IPO丨用创新科技助力中国光伏产业高质量发展

近年来,在“以科技创新引领现代化产业体系建设”的战略指引下,整个光伏行业持续推动技术迭代与生产力升级,朝着更高光电转化效率、更低成本加速迈进。 在此背景下,一批以技术驱动为第一生产力的光伏厂商们,在自身领域…

APP被DDoS攻击时,企业应该如何防护?

某平台遭到分布式拒绝服务攻击,大规模、持续性的攻击,导致平台的APP、网站的部分用户出现间歇性无法登录、加载失败或缓慢等情况。据了解,平台在一个月的时间内陆续遭受到近30次的网络攻击。在这段时间内,平台不断地接收到短时间、…

虚拟货币:数字金融时代的新工具

在数字化时代的到来之后,虚拟货币逐渐成为了一种广为人知的金融工具。虚拟货币是一种数字化的资产,它不像传统货币那样由政府或中央银行发行和监管。相反,虚拟货币通过密码学技术和分布式账本技术来实现去中心化的发行和交易。 虚拟货币的代…

Nodejs 第六十三章(串口技术)

串口介绍 串口技术是一种用于在计算机和外部设备之间进行数据传输的通信技术。它通过串行传输方式将数据逐位地发送和接收。 常见的串口设备有,扫描仪,打印机,传感器,控制器,采集器,电子秤等 SerialPort …

ES6 关于Class类的继承 extends(2024-04-10)

1、简介 类Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多。 class Foo {constructor(x, y) {this.x x;this.y y;console.log(父类构造函数)}toString() {return ( this.x …

MyBatis 等类似的 XML 映射文件中,当传入的参数为空字符串时,<if> 标签可能会导致 SQL 语句中的条件判断出现意外结果。

问题 传入的参数为空字符串,但还是根据参数查询了。 原因 在 XML 中使用 标签进行条件判断时,需要明确理解其行为。在 MyBatis 等类似的 XML 映射文件中, 标签通常用于动态拼接 SQL 语句的条件部分。当传入的参数 riskLevel 为空字符串时…

rebase和merge的区别

合并分支用rebase还是merge? 实际开发工作的时候,我们都是在自己的分支开发,然后将自己的分合并到主分支,那合并分支用2种操作,这2种操作有什么区别呢? git上新建一个项目,默认是有master分支…

如何在 YouTube、Medium、Twitter 和 Linkedin 上使用 ChatGPT 赚钱

人工智能SEO:未来内容优化的革命 介绍 在当今的数字时代,利用 ChatGPT 等人工智能工具已经成为在线内容创建和货币化领域的游戏规则改变者。 本指南探讨了如何在 YouTube、Medium、Twitter 和 Linkedin 等各种平台上有效使用 ChatGPT,不仅可以…

猫咪可以每天吃冻干吗?2024最全攻略这几款低调有实力

冻干猫粮近年来逐渐受到养猫人的青睐,其高品质的特性赢得了广大猫主人的认可。对于像我这样的养猫达人来说,早已尝试并认可了冻干喂养。但对于新手来说,他们可能会感到困惑:冻干到底是什么?猫咪可以每天吃冻干吗&#…

Canal的使用场景!!!

1、保持redis和mysql连接的一致性:通常使用延迟双删功能(具有弊端) 解决方案:可以使用canal监听数据库的变化(删改),一旦出现此类操作,立即删除redis中的对应数据,直至下…

【java工具-灵活拉取数据库表结构和数据】

需求: 假设我们现在有一个需求,需要快速拉取数据库的某些表建表语句,和数据,平时做备份之类; 我这边自己写了个工具,不多废话,也不整虚的, 直接看代码: package com.…

Elasticsearch8.x 设置密码

文章目录 一、环境说明二、使用elasticsearch-reset-password工具修改1、elasticsearch-reset-password工具位置2、设置密码 一、环境说明 elasticsearch版本:8.13.0 系统版本:Ubuntu 18.04.6 二、使用elasticsearch-reset-password工具修改 1、elast…

【汇编语言实战】求三个已知数最大值

C语言描述该程序流程&#xff1a; #include <stdio.h> int main() {int a10,b20,c15;//scanf("%d %d",&a,&b);if(a>b){if(a>c){printf("%d",c);}else{printf("%d",a);}}else{if(b>c){printf("%d",b);}else{pr…

Pinctrl子系统、GPIO子系统概念

Pinctrl概念&#xff1a; 无论是哪种芯片&#xff0c;都有类似图 16.1 的结构&#xff1a; 要想让 pinA 、 B 用于 GPIO &#xff0c;需要设置 IOMUX 让它们连接到 GPIO 模块&#xff1b; 要想让 pinA 、 B 用于 I2C &#xff0c;需要设置 IOMUX 让它们连接到 …