RPC通讯基础原理

1.RPC(Remote Procedure Call)概述

        RPC是一种通过网络从远程计算机上调用程序的技术,使得构建分布式计算更加容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性,提供一种透明调用机制,让使用者不必显式的区分本地调用和远程调用;

1.1 RPC优点

  • RPC框架一般使用长连接,不必每次通信都三次握手,减少网络开销;
  • RPC框架一般都有注册中心,有丰富的监控管理、发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作,协议私密安全性较高;
  • RPC协议简单内容小效率高,服务化架构、服务化治理;
  • RPC可以基于TCP实现(Dubbo、Thrift)也可以基于HTTP2(gRPC)

1.2 RPC框架

  • Dubbo:阿里巴巴开发的开源RPC框架,支持Java语言 ;
  • Thrift:FaceBook开发的跨语言RPC框架,支持多种语言;
  • gRPC:Google开发的跨语言RPC框架,支持多种语言;
  • SpringCloud:Pivotal开发的RPC框架,提供了丰富的生态组件

1.3 RPC调用流程

所涉及的技术:

  1. 动态代理:生成Client Stub(客户端存根)和Server Stub(服务端存根)的时候需要用到java动态代理技术。
  2. 序列化:在网络中,所有的数据都将会被转化为字节进行传送,需要对这些参数进行序列化和反序列化操作;目前主流高效的开源序列化框架有Kryo、fastjson、Hessian、Protobuf等。
  3. NIO通信:Java 提供了 NIO 的解决方案,Java 7 也提供了更优秀的 NIO.2 支持。可以采用Netty或者mina框架来解决NIO数据传输的问题。开源的RPC框架Dubbo就是采用NIO通信,集成支持netty、mina、grizzly。
  4. 服务注册中心:通过注册中心,让客户端连接调用服务端所发布的服务。主流的注册中心组件:Redis、Nacos、Zookeeper、Consul 、Etcd。Dubbo采用的是ZooKeeper提供服务注册与发现功能。
  5. 负载均衡:在高并发的场景下,需要多个节点或集群来提升整体吞吐能力。
  6. 健康检查:健康检查包括,客户端心跳和服务端主动探测两种方式。 

2.序列化技术

        网络传输中,数据必须采用二进制形式,序列化技术就负责对数据进行序列化(对象转成二进制数据)和反序列化(二进制数据转回对象);

2.1 常用的序列化技术

2.1.1 JDK原生序列化

public static void main(String[] args) throws IOException,ClassNotFoundException {String basePath = "D:/TestCode";FileOutputStream fos = new FileOutputStream(basePath +"tradeUser.clazz");TradeUser tradeUser = new TradeUser();tradeUser.setName("Mirson");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(tradeUser);oos.flush();oos.close();FileInputStream fis = new FileInputStream(basePath +"tradeUser.clazz");ObjectInputStream ois = new ObjectInputStream(fis);TradeUser deStudent = (TradeUser) ois.readObject();ois.close();System.out.println(deStudent);
}
  • 首先序列化的对象必须实现java.io.Serializable接口;
  • 通过ObjectOutputStream和ObjectInputStream的读和写来对对象进行序列化和反序列化;
  • 对象的序列化id须一致才能反序列化(private static final long serialVersionUID);
  • 序列化不会保存静态变量,变量前加Transient关键字可以不序列化该变量

2.1.2 JSON序列化

        如常用的fastjson

        JSON序列化具有较好的扩展性、可读性和通用性,但占用空间多、效率低;

2.1.3 Hessian2序列化

        Hessian 是一个动态类型,二进制序列化,并且支持跨语言特性的序列化框架。
        Hessian 性能上要比 JDK、JSON 序列化高效很多,并且生成的字节数也更小。有非常好的兼容性和稳定性,所以 Hessian 更加适合作为 RPC 框架远程通信的序列化协议。

TradeUser tradeUser = new TradeUser();
tradeUser.setName("Mirson");
//tradeUser对象序列化处理
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(bos);
output.writeObject(tradeUser);
output.flushBuffer();
byte[] data = bos.toByteArray();
bos.close();
//tradeUser对象反序列化处理
ByteArrayInputStream bis = new ByteArrayInputStream(data);
Hessian2Input input = new Hessian2Input(bis);
TradeUser deTradeUser = (TradeUser) input.readObject();
input.close();
  • 不支持Linked对象,如LInkedHashMap、LinkeHashSet等,但可以通过CollectionSerializer类修复
  • 不支持Locale类,可以通过扩展ContextSerializerFactory类修复
  • Byte/Short在反序列化的时候会转成Integer

2.1.4 Protobuf序列化

        google推出的开源序列库,序列化后的体积小、序列化速度快;

3.动态代理

        通过运行时动态创建代理对象,进行额外处理(如增强功能、日志记录、事务管理、权限控制等),再将调用传递给实际的目标对象;

3.1 常用的动态代理技术

3.1.1 JDK动态代理

        JDK动态代理为Java标准库的一部分,不需要引入外部依赖;

public class JdkProxyTest {/*** 定义用户的接口*/public interface User {String job();}/*** 实际的调用对象*/public static class Teacher {public String invoke(){return "i'm Teacher";}}/*** 创建JDK动态代理类*/public static class JDKProxy implements InvocationHandler {private Object target;JDKProxy(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[]paramValues) {return ((Teacher)target).invoke();}}public static void main(String[] args){// 构建代理器JDKProxy proxy = new JDKProxy(new Teacher());ClassLoader classLoader = ClassLoaderUtils.getClassLoader();// 生成代理类User user = (User) Proxy.newProxyInstance(classLoader, newClass[]{User.class}, proxy);// 接口调用System.out.println(user.job());}
}

3.1.2 Cglib动态代理

        Cglib是一个强大的、高性能代码生成包,广泛被许多AOP框架使用,支持方法级别的拦截。

3.1.3 Javassist动态代理

        一个开源的分析、编辑和创建Java字节码的类库。javassist是jboss的一个子项目,它直接使用java编码的形式,不需要了解虚拟机指令,可以动态改变类的结构,或者动态生成类。Javassist 的定位是能够操纵底层字节码,所以使用起来并不简单,Dubbo 框架的设计者为了追求性能花费了不少精力去适配javassist。

3.1.4 Byte Buddy 字节码增强库

        Byte Buddy是致力于解决字节码操作和 简化操作复杂性的开源框架。Byte Buddy 目标是将显式的字节码操作隐藏在一个类型安全的领域特定语言背后。它属于后起之秀,在很多优秀的项目中,像Spring、Jackson 都用到了 Byte Buddy 来完成底层代理。相比 Javassist,Byte Buddy 提供了更容易操作的 API,编写的代码可读性更高。

3.2 不同动态代理技术对比

        Byte Buddy > CGLIB > Javassist> JDK

  • 数据来自 Blog | JRebel & XRebel by Perforce

4.服务注册发现

        在服务较多的项目中使得客户端能够及时感知服务端的变化,及时获取服务节点的连接信息;

        目前用的比较多的就是Nacos和ZooKeeper;

5.网络IO模型

        包括同步阻塞IO(BIO)、同步非阻塞IO(NIO)、IO多路复用、信号驱动IO、异步非阻塞IO(AIO)

        阻塞:请求了之后线程一直等待回复;

        非阻塞:请求之后立刻相应,线程可以干别的,并且轮询read是否完成;

5.1 IO多路复用

        IO多路复用(I/O Multiplexing)是一种允许单个线程管理多个输入输出(I/O)操作的技术。它通过将多个 I/O 操作注册到一个选择器(Selector)上,然后阻塞等待其中任何一个 I/O 操作就绪,从而实现高效的 I/O 管理。IO多路复用在高并发服务器中非常有用,因为它可以显著减少系统资源的消耗,提高系统的吞吐量。

        使用select进行IO请求与同步阻塞模式类似,甚至单条速度由于添加了监视socket效率更低,但是用户可以在一个线程内同事处理多个socket的IO请求,实现类似多线程的同步阻塞;

5.1.1 IO多路复用的实现方式

selectpollepoll(仅Linux)
操作方式遍历遍历回调
底层实现bitmap数组红黑树
IO效率每次调用都线性遍历,O(n)时间复杂度每次调用都线性遍历,O(n)时间复杂度每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,O(1)时间复杂度
最大连接数1024(x86)或2048(x64)无上限无上限
fd拷贝每次调用select,都需要把fd集合从用户态拷贝到内核态每次调用poll,都需要把fd集合从用户态拷贝到内核态调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

5.1.2 IO多路复用与阻塞IO对比

        IO多路复用更适合高并发的场景,可以用较少的线程处理较多的socket的IO请求;阻塞IO每处理一个socket的IO请求都会阻塞线程,适合并发量低的场景,不需要发起大量select调用,这种场景下阻塞IO开销比IO多路复用低;

        RPC调用大多情况下是高并发的场景,所以RPC框架一般会选择IO多路复用的方式,而且在linux环境下要使用epoll方式;

5.2 零拷贝

        系统内核处理IO操作包含两个阶段:等待数据、拷贝数据

  • 等待数据:系统内核在等待网卡接收到数据后,把数据写到内核中;
  • 拷贝数据:系统内核在获取到数据后,将数据拷贝到用户进程的空间中;

        进程的每一次写操作 都会把数据写到用户空间的缓冲区内,再由CPU将数据拷贝到系统内核的缓冲区,之后再由DMA将数据拷贝到网卡中,最后由网卡发送出去;

        零拷贝指的就是取消用户空间与内核空间之间的数据拷贝操作;

        Netty中的零拷贝,与此处的操作系统的零拷贝有一定区别,Netty的零拷贝实际上是对用户空间中数据操作的优化,Netty的接收和发送ByteBuffer采用DIRECTBUFFERS,使用堆外的直接内存(内存对象分配在JVM中堆以外的内存)进行Socket读写,不需要进行字节缓冲区的二次拷贝;

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

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

相关文章

Leetcode 跳跃游戏 二

核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 这段代码解决的是“跳跃游戏 II”(Leetcode第45题),其核心任务是找出从数组的起点跳到终点所需的最小跳跃次数。 class Solution {public int jump(int[] nums) {//首先处理特殊情…

【文化课学习笔记】【化学】选必三:同分异构体的书写

【化学】选必三:同分异构体的书写 如果你是从 B 站一化儿笔记区来的,请先阅读我在第一篇有机化学笔记中的「读前须知」(点开头的黑色小三角展开):链接 链状烃的取代和插空法 取代法 一取代物 甲烷、乙烷、丙烷、丁烷的种类 甲烷:只…

【AAOS】Android Automotive 14模拟器源码下载及编译

源码下载 repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r20 repo sync -c --no-tags --no-clone-bundle 源码编译 source build/envsetup.sh lunch sdk_car_x86_64-trunk_staging-eng make -j8 运行效果 emualtor Home All apps …

计算机是如何输入存储输出汉字、图片、音频、视频的

计算机是如何输入存储输出汉字、图片、音频、视频的 为了便于理解,先了解一下计算机的组成。 冯诺依曼计算机的五大组成部分。分别是运算器、控制器、存储器、输入设备和输出设备。参见下图: 一、运算器 运算器又称“算术逻辑单元”,是计算…

Android Camera2在textureView中的预览和拍照

Camera2预览和拍照 1、Camera2相机模型2、Camera2的重要类3、Camera2调用流程4、Camera2调用实现 1)定义TextureView作为预览界面2)设置相机参数3)开启相机4)开启相机预览5)实现PreviewCallback6)拍照 1、Camera2相机模型 解释上诉示意图,假如想要同时拍摄两张不同…

图像及视频的基本操作

文章目录 一、认识计算机中的图像二、图像数据的读取三、数据读取-视频四、图像的其他操作 一、认识计算机中的图像 一张彩色图片是由很多个像素点组合而成的,而一个像素点是由R G B三个通道组成。RGB代表红色(Red)、绿色(Green&a…

【远程监控新体验】OpenObserve结合内网穿透无公网IP远程访问全攻略

文章目录 前言1. 安装Docker2. Docker镜像源添加方法3. 创建并启动OpenObserve容器4. 本地访问测试5. 公网访问本地部署的OpenObserve5.1 内网穿透工具安装5.2 创建公网地址6. 配置固定公网地址前言 本文主要介绍如何在Linux系统使用Docker快速本地化部署OpenObserve云原生可观…

MacOS RocketMQ安装

MacOS RocketMQ安装 文章目录 MacOS RocketMQ安装一、下载二、安装修改JVM参数启动关闭测试关闭测试测试收发消息运行自带的生产者测试类运行自带的消费者测试类参考博客:https://blog.csdn.net/zhiyikeji/article/details/140911649 一、下载 打开官网,…

并发-线程

1, 线程 线程(thread)也是并发的一种形式,线程是比进程更小的活动单位,一个进程中可以有多个线程,线程是进程内部的一个执行分支。 一个进程刚开始时只有一个线程(称之为主线程),后续的代码中可以创建新的线程,可以指…

git提交到github个人记录

windows下git下载 1.进入git官网https://git-scm.com/downloads/win 一直默认选项即可 2.在settings中SSH and GPG keys中Add SSH key 3.选择git cmd git使用 1.配置用户名,和邮箱 git config --global user.email "youexample.com" git config --g…

aws(学习笔记第六课) AWS的虚拟私有,共有子网以及ACL,定义公网碉堡主机子网以及varnish反向代理

aws(学习笔记第六课) AWS的虚拟私有,共有子网以及ACL,定义公网碉堡主机子网以及varnish反向代理 学习内容: AWS的虚拟私有,共有子网以及ACL定义公网碉堡主机子网,私有子网和共有子网以及varnish反向代理 1. AWS的虚拟…

深入理解WPF中的命令机制

Windows Presentation Foundation(WPF)是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础,具有强大的图形和媒体处理能力。在WPF中,“命令”是一个重要的概念,它为应用程序开发…

如何在算家云搭建Video-Infinity(视频生成)

一、模型介绍 Video-Infinity是一个先进的视频生成模型,使用多个 GPU 快速生成长视频,无需额外训练。它能够基于用户提供的文本或图片提示,创造出高质量、多样化的视频内容。 二、模型搭建流程 1.大模型 Video-Infinity 一键使用 基础环境…

Nest.js 实战 (十四):如何获取客户端真实 IP

问题解析 在 Nest.js 应用中,当你试图通过 request.ip 获取客户端的 IP 地址时,如果总是返回 ::1 或者 ::ffff:127.0.0.1,这通常意味着请求来自本地主机。 因为在前后端分离应用中,前端请求后端服务一般的做法都是通过代理&…

SQL进阶技巧:如何删除第N次连续出现NULL值所存在的行?

目录 0 场景描述 1 数据准备 2 问题分析 问题拓展:如何删除第2次、第3次、第N次连续出现NULL值所在的行? 3 小结 0 场景描述 有下面的场景: 我们希望删除某id中连续存在NULL值的所有行,但是保留第一次出现不为NULL值的以下所有存在NULL值的行。具体如下图所示: 如…

Leetcode 判断子序列

通过双指针来判断字符串s是否是字符串t的子序列。 算法思想: 双指针法: 我们使用两个指针i和j分别遍历字符串s和t。初始时,i指向s的第一个字符,j指向t的第一个字符。 匹配字符: 每次比较s[i]和t[j]: 如果…

大数据治理-数据质量管理

目录 一、定义数据质量 1.1 数据质量的定义 1.2 数据质量的重要性 二、常见的数据质量问题 2.1 数据不准确 2.2 数据不完整 2.3 数据不一致 2.4 数据不及时 2.5 数据无效 2.6 数据重复 三、数据清洗与转换 3.1 数据清洗 3.1.1 数据审计 3.1.2 数据验证 3.1.3 数…

uniapp小程序自定义聚合点

注&#xff1a; 1.默认的聚合点可以点击自动展示子级点位&#xff0c;但是自定义的聚合点在ios上无法触发markerClusterClick的监听&#xff0c;至今未解决&#xff0c;不知啥原因 2.ios和安卓展示的点位样式还有有差别 源码附上 <template><view class"marke…

Linux - 环境变量 | 命令行参数 | 进程基础

文章目录 一、了解冯诺依曼体系结构1、概念2、对数据层面3、实例二、操作系统1、概念2、设计OS的目的3、定位4、操作系统怎么管理&#xff1f; 三、进程1、概念2、怎么管理进程3、描述进程-PCB4、描述进程怎么运行&#xff08;粗略&#xff09;5、进程属性6、创建子进程7、创建…

PDF文件为什么不能编辑是?是啥原因导致的,有何解决方法

PDF文件格式广泛应用于工作中&#xff0c;但有时候我们可能遇到无法编辑PDF文件的情况。这可能导致工作效率降低&#xff0c;特别是在需要修改文件内容时显得尤为棘手。遇到PDF不能编辑时&#xff0c;可以看看是否以下3个原因导致的。 一、文件受保护 有些PDF文件可能被设置了…