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;
        }
        @Override
        public 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, new
                Class[]{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读写,不需要进行字节缓冲区的二次拷贝;

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

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

相关文章

数据字典是什么?和数据库、数据仓库有什么关系?

一、数据字典的定义及作用 数据字典是一种对数据的定义和描述的集合,它包含了数据的名称、类型、长度、取值范围、业务含义、数据来源等详细信息。 数据字典的主要作用如下: 1. 对于数据开发者来说,数据字典包含了关于数据结构和内容的清晰…

centos7上安装minio及使用方法介绍

MinIO是一个高性能、分布式对象存储系统,可以用于存储大量的非结构化数据,例如图片、视频、日志文件等。它是一个开源项目,可以在各种环境中部署,包括本地服务器、公共云和混合云环境。 github仓库地址:https://github.com/minio 一、安装说明 本章教程,是在Linux Centos…

AutoCompleteTextView

AutoCompleteTextView的学习 简单使用AutoCompleteTextView mainactivity.java import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.view.WindowManager; import android.widget.ArrayAdapter; import android.widget.AutoCompleteT…

【环境搭建】远程服务器搭建ElasticSearch

参考: 非常详细的阿里云服务器安装ElasticSearch过程..._阿里云服务器使用elasticsearch-CSDN博客 服务器平台:AutoDL 注意: 1、切换为非root用户,su 新用户名,否则ES无法启动 2、安装过程中没有出现设置账号密码…

“探索Adobe Photoshop 2024:订阅方案、成本效益分析及在线替代品“

设计师们对Adobe Photoshop这款业界领先的图像编辑软件肯定不会陌生。如果你正考虑加入Photoshop的用户行列,可能会对其价格感到好奇。Photoshop的价值在于其强大的功能,而它的价格也反映了这一点。下面,我们就来详细了解一下Adobe Photoshop…

Chromium 如何查找V8 引擎中JavaScript 标准内置对象

JavaScript 标准内置对象 - JavaScript | MDN (mozilla.org) 一、JavaScript 标准内置对象 本章介绍和说明了 JavaScript 中所有的标准内置对象、以及它们的方法和属性。 这里的术语“全局对象”(或标准内置对象)不应与 global 对象混淆。这里的“全局…

07 django管理系统 - 部门管理 - 搜索部门

在dept_list.html中&#xff0c;添加搜索框 <div class"container-fluid"><div style"margin-bottom: 10px" class"clearfix"><div class"panel panel-default"><!-- Default panel contents --><div clas…

【学习笔记】什么是MongoDB

文章目录 MongoDB 简介体系结构数据模型MongoDB 的特点 MongoDB 简介 学习一个东西就跟认识一个人一样&#xff0c;下面有情MongoDB来做个自我介绍 大家好&#xff0c;俺是MongoDB&#xff0c;是一个开源、高性能、无模式的文档型数据库&#xff0c;当初的设计俺就是用于简化开…

6.计算机网络_UDP

UDP的主要特点&#xff1a; 无连接&#xff0c;发送数据之前不需要建立连接。不保证可靠交付。面向报文。应用层给UDP报文后&#xff0c;UDP并不会抽象为一个一个的字节&#xff0c;而是整个报文一起发送。没有拥塞控制。网络拥堵时&#xff0c;发送端并不会降低发送速率。可以…

UNI VFX Missiles Explosions for Visual Effect Graph

Unity URP和HDRP的通用视觉效果 使用在视觉效果图中制作的高性能GPU粒子系统。 无需进入视觉效果图编辑器即可轻松自定义VFX。 使用(VFX)事件——一个游戏对象可存储多个效果,这些效果可通过C#或视觉脚本触发。 总共32个事件(不包括“停止”事件)。 ❓ 什么是(VFX)事件?…

前端开发学习(一)VUE框架概述

一、MVC模式与MVVM模式 1.1mvc模式 MVC模式是移动端应用广泛的软件架构之一&#xff0c;MVC模式将应用程序划分为3部分:Model(数据模型)、View(用户界面视图)和Controller(控制器)。MVC模式的执行过程是将View层展示给用户&#xff0c;也就是通过 HTML页面接受用户动作&#…

【算法篇】贪心类(1)(笔记)

目录 一、理论基础 1. 大纲 2. 求解步骤 二、Leetcode 题目 1. 分发饼干 2. 摆动序列 3. 最大子序和 4. 买卖股票的最佳时机 II 5. 跳跃游戏 6. 跳跃游戏 II 7. K 次取反后最大化的数组和 8. 加油站 9. 分发糖果 一、理论基础 1. 大纲 2. 求解步骤 将问题分解为…

CTFHUB技能树之SQL——MySQL结构

开启靶场&#xff0c;打开链接&#xff1a; 先判断一下是哪种类型的SQL注入&#xff1a; 1 and 11# 正常回显 1 and 12# 回显错误&#xff0c;说明是整数型注入 判断一下字段数&#xff1a; 1 order by 2# 正常回显 1 order by 3# 回显错误&#xff0c;说明字段数是2列 知道…

【Axure高保真原型】标签管理可视化驾驶舱长页面案例

今天和大家分享标签管理可视化驾驶舱长页面案例的原型模板&#xff0c;包括我的工作、通告消息、标签总体调用趋势、标签应用业务场景对比、标签使用排名、各个标签使用情况……具体效果可以点击下方视频观看或打开下方预览地址查看哦 【原型效果】 【Axure高保真原型】标签管…

Kaggle Python练习:字符串和字典(Exercise: Strings and Dictionaries)

文章目录 问题&#xff1a;搜索特定单词并定位思路代码实现官方代码代码解析 更进一步 问题&#xff1a;搜索特定单词并定位 一位研究人员收集了数千篇新闻文章。但她想将注意力集中在包含特定单词的文章上。完成以下功能以帮助她过滤文章列表。 您的函数应满足以下条件&…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,1-8

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

Excel筛选数据时用到分类汇总值

举个例子;现有分类产品销售额汇总表如下所示&#xff1a; 请找出销售额大于所在分类平均销售额的产品&#xff1a; 使用 SPL XLL&#xff0c;输入公式&#xff1a; spl("E(?1).group(CategoryName).(a~.avg(ProductSales),~.select(ProductSales>a)).conj()",A…

R语言详解predict函数

R语言中predict函数在建立模型&#xff0c;研究关系时常用。但是不同type得到的结果常常被混为一谈&#xff0c;接下来&#xff0c;探讨predict得到的不同结果。 #数据 set.seed(123) n<-1000 age<-rnorm(n,mean50,sd10) gender<-rbinom(n,1,0.5) disease<-rbinom…

MFC工控项目实例二十四模拟量校正值输入

承接专栏《MFC工控项目实例二十三模拟量输入设置界面》 对模拟量输入的零点校正值及满量程对应的电压值进行输入。 1、在SenSet.h文件中添加代码 #include "BtnST.h" #include "ShadeButtonST.h"/ // SenSet dialogclass SenSet : public CDialog { // Co…

STM32——关于I2C的讲解与应用

1、什么是I2C&#xff1f; I2C(Inter&#xff0d;Integrated Circuit)是一种通用的总线协议。它是由Philips(飞利浦)公司&#xff0c;现NXP(恩智浦)半导体开发的一种简单的双向两线制总线协议标准。是一种半双工的同步通信协议。 2、I2C协议标准 I2C协议使用两根总线线路&am…