当前位置: 首页 > news >正文

RPC通信原理(一)

RPC通信原理

RPC的概念

如果现在我有一个电商项目,用户要查询订单,自然而然是通过Service接口来调用订单的实现类。

我们把用户模块和订单模块都放在一起,打包成一个war包,然后再tomcat上运行,tomcat占有一个进程,这个项目也是在这个进程中运行的,模块之间的调用也是在进程的本地进行调用,那么如果我是一个分布式项目该怎么解决呢?

现在用户和订单模块部署在两台服务器上,这时候用户模块就不能直接调用订单模块了,只能够通过网络来进行调用,而RPC就是用来干这个事情的,通过RPC来进行服务之间的远程调用

特点:

  • 把远程实现搬到了本地,效果上远程调用和本地调用没区别
  • 这里的搬运到了本地不是真的把代码CV到调用者本地,而是RPC的一种无侵入式的抽象,调用者可以调用本地服务一样去调用远程的服务,其中的网络协议,数据传输等实现细节被RPC屏蔽掉。
  • 使用CS模式,客户端发起请求并传递参数,服务端接收参数后执行,并将执行结果返回
  • 底层网络通信细节对上层开发者屏蔽,上层开发者无需为这一交互过程做额外的编码,做到应用无侵入

RPC的应用场景有哪些?

需要远程通信的各类场景

小结

RPC中的关键技术点

调用过程如下:

调用流程总结:

首先客户端要远程调用这个接口,这个接口会由RPC底层动态代理实现远程调用,然后通过序列化数据,以及使用互相通信的协议编码,通过网络传输到对端服务器上,服务器从网络模块拿到数据,经过解码、反序列化一系列操作之后,调用这个函数的实现方法,把结果再次经过序列化和协议编码处理之后发送给客户端,客户端进行协议解码和反序列化得到数据。

小结

RPC中的高级特性

动态感知并且自动切换

当服务器压力小的时候可以减少RPC集群数量,当服务器压力大的时候可以增加RPC集群节点,这一过程都是自动完成的,这一功能依赖于注册中心

服务发现模块会监听注册中心,看注册中心时候发送消息给服务发现模块,当注册中心的配置发生变化之后,注册中心会像服务发现模块发送消息,告知它配置已经发生了修改,然后去重写拉取配置,写入本地缓存当中。

小结

RPC的优势

Zookeeper的注册原理及存储结构

Zookeeper是一个树形结构,通过路径+节点来标识一个节点。

https://www.runoob.com/w3cnote/zookeeper-tutorial.html

注册中心Dubbo会记录有哪些远程调用的接口,及其生产者和消费者,对于远程调用的接口是一个持久节点,会一直存在,而生产者和消费者却是临时节点,这是因为:

  • 容错与自动摘除

    • 当提供服务的生产者因为故障或正常关闭时,Zookeeper上的临时节点会自动删除。这样消费者(Consumer)从Zookeeper获取的服务列表中将不再包含已下线的服务提供者,实现了服务列表的自动更新和失效剔除。
  • 服务实例生命周期管理

    • 临时节点的存在与Zookeeper客户端会话绑定,当服务提供者的Zookeeper客户端会话中断(例如进程退出、网络断开等情况)时,对应的临时节点就会被清理,这与服务提供者的生命周期保持一致。
  • 负载均衡与集群伸缩性

    • 使用临时节点可以方便地支持集群环境下的动态扩容与缩容,新的服务提供者上线或者旧的提供者下线,都能迅速反映到服务注册中心,进而使得消费者能及时感知并调整访问策略。

Dubbo协议异步单一长连接原理与优势

2. 异步单一长连接原理

2.1 异步通信

Dubbo协议采用异步通信模型,即客户端发送请求后不需要等待服务端响应,可以立即进行其他操作。这种模型的核心在于使用了NIO(Non-blocking I/O)技术,通过事件驱动和回调机制来实现请求的并发处理。

具体来说,客户端在发送请求后,将请求信息注册到事件多路复用器上。当服务端响应到达时,事件多路复用器会触发相应的回调函数进行处理。这样一来,客户端就可以异步地处理多个请求,提高了系统的并发能力和吞吐量。

2.2 单一长连接

Dubbo协议使用单一长连接的方式来进行通信。所谓单一长连接,就是指客户端与服务端之间只建立一个TCP连接,并保持长时间的有效性。

这种设计方案有以下几个优势:

2.2.1 连接复用

由于只有一个TCP连接,不需要频繁地建立和关闭连接,避免了TCP连接的三次握手和四次挥手的开销。同时,连接的复用还可以减轻网络设备的负担,提高网络的利用率。

2.2.2 减少资源消耗

每个TCP连接都会占用一定的系统内存和CPU资源,如果每个请求都需要建立新的连接,那么系统资源开销将会非常大。而采用单一长连接的方式,可以大幅度降低资源的消耗,提高系统的稳定性和可伸缩性。

2.2.3 保证顺序性

由于Dubbo协议仅使用一个连接,发送的请求和接收的响应不会交错。这意味着请求和响应可以按照发送的顺序进行处理,不会出现乱序的情况。这在一些有序性要求较高的场景中非常重要。

3. 异步单一长连接的优势

异步单一长连接作为Dubbo协议的核心设计,具有以下几个显著的优势:

3.1 减少网络开销

采用异步通信模型和单一长连接方式可以减少网络的开销,避免了频繁地建立和关闭连接带来的额外开销。这对于海量请求的场景尤为重要,可以提升系统的性能和吞吐量。

3.2 提高系统的稳定性和可伸缩性

由于单一长连接减少了资源消耗,系统的稳定性和可伸缩性得到了提高。在高并发情况下,系统能够更好地承受请求的压力,同时也降低了系统崩溃的风险。

3.3 简化系统维护和监控

采用单一长连接的方式简化了系统的维护和监控工作。只需要关注一个TCP连接的状态和性能指标,而不需要管理多个独立的连接。这有助于提高运维效率和降低维护成本。

3.4 保证请求顺序性

由于异步通信模型和单一长连接的特性,Dubbo协议能够保证请求和响应的顺序性。这对于某些有序性要求的业务场景非常重要,例如金融交易系统中的订单处理。

长链接中断的情况:

  1. 服务端或客户端主动断开连接。
  2. 网络故障导致连接中断。
  3. 客户端(如消费方应用)或者服务端进程终止。

代理技术

JDK Proxy原理

//JDK的动态代理
public class JdkProxyTest {public static void main(String[] args) {//会将生成的class保存在工程根目录下的 com/sun/proxy 目录里面System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");BookService bookService=(BookService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), //类加载器new Class[]{BookService.class}, //要动态代理实现的方法new Handler() //要调用的方法实现);Book book=bookService.findById("100");System.out.println(book);}static class Handler implements InvocationHandler{@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//发起远程网络调用System.out.println("模拟发起网络远程调用");Book book=new Book();book.setId(args[0].toString());book.setName("斗破苍穹");book.setTitle("玄幻");book.setTag("玄幻");book.setContent("爽文");return book;}}
}

查看其代理类:

public final class $Proxy0 extends Proxy implements BookService {private static Method m1;private static Method m2;private static Method m0;private static Method m3;public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final boolean equals(Object var1) throws  {try {return (Boolean)super.h.invoke(this, m1, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}public final String toString() throws  {try {return (String)super.h.invoke(this, m2, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final int hashCode() throws  {try {return (Integer)super.h.invoke(this, m0, (Object[])null);} catch (RuntimeException | Error var2) {throw var2;} catch (Throwable var3) {throw new UndeclaredThrowableException(var3);}}public final Book findById(String var1) throws  {try {return (Book)super.h.invoke(this, m3, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");m3 = Class.forName("BookService").getMethod("findById", Class.forName("java.lang.String"));} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}

对上述代码精简一下:

public final class $Proxy0 extends Proxy implements BookService {private static Method m1;private static Method m2;private static Method m0;private static Method m3; //findById方法public $Proxy0(InvocationHandler var1) throws  {super(var1);}public final Book findById(String var1) throws  {try {return (Book)super.h.invoke(this, m3, new Object[]{var1});} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString");m0 = Class.forName("java.lang.Object").getMethod("hashCode");m3 = Class.forName("BookService").getMethod("findById", Class.forName("java.lang.String"));} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}}
}
super(var1);//查看一下这个函数,如下protected InvocationHandler h;protected Proxy(InvocationHandler h) {Objects.requireNonNull(h);this.h = h;}
    public final Book findById(String var1) throws  {try {return (Book)super.h.invoke(this, m3, new Object[]{var1}); //这里的h就是我们传递过来的Handler方法,也就是直接调用我们自己实现的handler方法} catch (RuntimeException | Error var3) {throw var3;} catch (Throwable var4) {throw new UndeclaredThrowableException(var4);}}

其他动态代理的解决方案

小结

相关文章:

RPC通信原理(一)

RPC通信原理 RPC的概念 如果现在我有一个电商项目,用户要查询订单,自然而然是通过Service接口来调用订单的实现类。 我们把用户模块和订单模块都放在一起,打包成一个war包,然后再tomcat上运行,tomcat占有一个进程&am…...

修改/etc/resolve.conf重启NetworkManager之后自动还原

我ping 百度报错: [rootk8snode1 ~]# ping baidu.com ping: baidu.com: Name or service not known很明显,这是DNS解析问题。 于是我修改 /etc/resolv.conf 文件后,执行完sudo systemctl restart NetworkManager,/etc/resolv.con…...

Web前端依赖版本管理最佳实践

本文需要读者懂一点点前端的构建知识: 1. package.json文件的作用之一是管理外部依赖;2. .npmrc是npm命令默认配置,放在工程根目录。 Web前端构建一直都是一个不难,但是非常烦人的问题,在DevOps、CI/CD领域。 烦人的是…...

多线程进阶

一.常见的锁策略 这里所讲的锁,不是一把具体的锁,而是锁的特性 1.乐观锁和悲观锁 悲观乐观是对锁冲突大小的预测 若预测锁冲突概率不大,就可能会少一些工作,那就是乐观锁;反之就是悲观锁 总是假设最坏的情况&…...

总结linux常用命令

Linux常用命令总结如下: 文件与目录操作: ls:列出目录内容cd:改变当前目录pwd:显示当前工作目录mkdir:创建新目录cp:复制文件或目录rm:删除文件或目录mv:移动或重命名文件…...

C++ 枚举

C 枚举 5.4.1普通枚举 枚举的定义:,枚举类型是通过enum关键字定义的,比如定义颜色类型 enum Color {RED, // 默认值为0GREEN, // 默认值为1BLUE // 默认值为2 }; Color myColor RED;注意: (1)括…...

Vue2在一个页面内动态切换菜单显示对应的路由组件

项目的需求是在一个页面内动态获取导航菜单,导航菜单切换的时候显示对应的路由页面,类似于tab切换的形式,切换的导航菜单和页面左侧导航菜单是同一个路由组件,只是放到了一个页面上,显示的个数不同,所有是动…...

执行任务赚积分C卷(JavaPythonC++Node.jsC语言)

现有N个任务需要处理,同一时间只能处理一个任务,处理每个任务所需要的时间固定为1。 每个任务都有最晚处理时间限制和积分值,在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。 可用于处理任务的时间有限,请问在有限的时间内,可获得的最多积分。 输入描述 第一…...

接口测试之文件下载

在工作中对于下载接口,经常会有这样的疑问:这类接口一般功能比较稳定,但是又比较重要,需要占用回归测试时间,有没有可替代的方式? 答案肯定是有的,可以从接口测试/UI自动化测试介入&#xff0c…...

算法思想总结:双指针算法

一、移动零 . - 力扣&#xff08;LeetCode&#xff09; 移动零 该题重要信息&#xff1a;1、保持非0元素的相对位置。2、原地对数组进行操作 思路&#xff1a;双指针算法 class Solution { public:void moveZeroes(vector<int>& nums){int nnums.size();for(int cur…...

python中的zip函数

1.zip&#xff08;&#xff09;同时迭代多个列表、字典等 使用zip()可以同时迭代多个可迭代对象&#xff0c;如列表、字典。 注意&#xff1a;当若干个可迭代对象的长度不相等时&#xff0c;zip()函数会停止在最短的可迭代对象。 例子&#xff1a; # 定义可迭代对象 numbers …...

Element 选择季度组件

<template><el-dialogtitle"选择季度":show-close"false":close-on-click-modal"false":close-on-press-escape"false":visible"visiable"class"dialog list"append-to-body><div><div>&…...

4.MongoDB中16个常用CURD

基本的CURD 作为一个非专业的DBA&#xff0c;我们只需要会一些基本的curd就行&#xff0c;专业的内容还是需要专业的人去干的。CRUD 也就是增删改查&#xff0c;这是数据库最基本的功能&#xff0c;查询还支持全文检索&#xff0c;GEO 地理位置查询等。 01创建库 无需单独创…...

Tomcat数据源笔记

Tomcat数据源笔记 连接池的概念 连接池是一种由容器提供的机制&#xff0c;用于管理数据库连接对象的集合。连接池的主要作用是在应用程序需要与数据库进行交互时&#xff0c;提供可复用的连接对象&#xff0c;从而减少每次建立数据库连接的开销。 连接池的工作原理 连接池的…...

Spring-Kafka笔记整理

引入依赖<dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId> </dependency>配置application.propertiesspring.kafka.bootstrap-servers192.168.99.51:9092编写kafka的配置类Configuration …...

已解决org.apache.hadoop.hdfs.protocol.QuotaExceededException异常的正确解决方法,亲测有效!!!

已解决org.apache.hadoop.hdfs.protocol.QuotaExceededException异常的正确解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 目录 问题分析 报错原因 解决思路 解决方法 总结 博主v&#xff1a;XiaoMing_Java 问题分析 在使用Hadoop分布式文件系统&a…...

GitHub打不开的解决方案(超简单)

在国内&#xff0c;github官网经常面临打不开或访问极慢的问题&#xff0c;不挂VPN&#xff08;梯子&#xff0c;飞机&#xff0c;魔法&#xff09;使用体验极差&#xff0c;那有什么好办法解决github官网访问不了的问题&#xff1f;今天小布教你几招轻松访问github官网。 git…...

Unity开发一个FPS游戏之二

在之前的文章中,我介绍了如何开发一个FPS游戏,添加一个第一人称的主角,并设置武器。现在我将继续完善这个游戏,打算添加敌人,实现其智能寻找玩家并进行对抗。完成的效果如下: fps_enemy_demo 下载资源 首先是设计敌人,我们可以在网上找到一些好的免费素材,例如在Unity…...

STM32F103 CubeMX 使用USB生成鼠标设备

STM32F103 CubeMX 使用USB生成鼠标设备 1 配置cubeMX1.1配置外部晶振&#xff0c;配置debug口1.2 配置USB1.3 配置芯片的时钟1.4 生成工程 2. 编写代码2.1 添加申明2.2 main函数代码 1 配置cubeMX 1.1配置外部晶振&#xff0c;配置debug口 1.2 配置USB 1.3 配置芯片的时钟 需…...

HJXH-E1/U静态信号继电器 面板安装 辅助电源220VDC 启动电压220VDC JOSEF约瑟

HJXH系列静态信号继电器 HJXH-61/U静态信号继电器&#xff1b; HJXH-61/I静态信号继电器&#xff1b; HJXH-62/U静态信号继电器&#xff1b; HJXH-62/I静态信号继电器&#xff1b; HJXH-E1/U静态信号继电器&#xff1b; HJXH-E1/I静态信号继电器&#xff1b; HJXH-E2/U静态信号…...

SpringBoot3下Kafka分组均衡消费实现

首先添加maven依赖&#xff1a; <dependency><groupId>org.springframework.kafka</groupId><artifactId>spring-kafka</artifactId><version>2.8.11</version><exclusions><!--此处一定要排除kafka-clients&#xff0c;然…...

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:GridItem)

网格容器中单项内容容器。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。仅支持作为Grid组件的子组件使用。 子组件 可以包含单个子组件。 接口 GridItem GridItem(value?: GridItemOptions)…...

Qt 使用RAW INPUT获取HID触摸屏,笔设备,鼠标的原始数据,最低受支持的客户端:Windows XP [仅限桌面应用]

在开发绘图应用程序时&#xff0c;经常会需要读取笔设备的数据&#xff0c;通过对笔数据的解析&#xff0c;来判断笔的坐标&#xff0c;粗细。如果仅仅只是读取鼠标的坐标&#xff0c;就需要人为在应用程序端去修改笔的粗细&#xff0c;并且使用体验不好&#xff0c;如果可以实…...

easyexcel导出excel文件到s3服务器

导出excel文件是开发中常见的需求 常见的做法一般是直接通过请求接口响应对象HttpServletResponse把文件输出 我们可以使用原生的poi工具类操作.也可以使用easypoi.easyexcel等基于poi二次封装的工具处理 下面是代码 /*** 导出列表** param request* param response*/Overri…...

xss.haozi.me靶场“0x0B-0x12”通关教程

君衍. 一、0x0B 实体编码绕过二、0x0C script绕过三、0x0D 注释绕过四、0X0E ſ符号绕过五、0x0F 编码解码六、0x10 直接执行七、0x11 闭合绕过八、0x12 闭合绕过 XSS-Labs靶场“1-5”关通关教程 XSS-Labs靶场“6-10”关通关教程 Appcms存储型XSS漏洞复现 XSS-Labs靶场“11-13、…...

linux--redhat系统Yum源配置

1&#xff09;说明 redhat yum命令使用报错解决-重新配置yum源 解决--更改yum源 2&#xff09;更改yum源 &#xff08;1&#xff09;进入源目录 cd /etc/yum.repos.d/ &#xff08;2&#xff09;备份 redhat 默认源 mv redhat.repo redhat.repo-bak &#xff08;3&#xff09;…...

el-Switch 开关二次确认

前言 最近在做毕设&#xff0c;有个需求是点击按钮控制用户的状态是否禁用&#xff0c;就看到element有个switch组件可以改造一下&#xff0c;就上网看了一下&#xff0c;结果为了这个效果忙活了很久。。。所以说记录一下&#xff0c;让大家少踩坑。 前置条件 先看完我的需求再…...

(二)丶RabbitMQ的六大核心

一丶什么是MQ Message Queue(消息队列&#xff09;简称MQ&#xff0c;是一种应用程序对应用程序的消息通信机制。在MQ中&#xff0c;消息以队列形式存储&#xff0c;以便于异步传输&#xff0c;在MQ中&#xff0c;发布者&#xff08;生产者&#xff09;将消息放入队列&#xff…...

微信小程序实现上下手势滑动切换

效果图 思路 实现一个微信小程序的复合滚动页面&#xff0c;主要通过Swiper组件实现垂直方向的轮播功能&#xff0c;每个轮播项内部使用Scroll-View组件来展示可垂直滚动的长内容&#xff0c;如图片和文本。 代码 <!-- wxml --> <view class"swiper-container…...

详解命令docker run -d --name container_name -e TZ=Asia/Shanghai your_image

docker run 是Docker的主要命令&#xff0c;用于从镜像启动一个新的容器。下面详细解释并举例说明 -d, --name, -e TZ 参数的用法&#xff1a; -d 或 --detach&#xff1a; 这个标志告诉Docker以守护进程&#xff08;后台&#xff09;模式运行容器。这意味着当你执行 docker ru…...