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

RPC框架的核心是什么

文章目录

  • 什么是 RPC
  • 封装的艺术(如何隐藏底层逻辑)
  • 协议的实现
  • 序列化和反序列化(编解码)
  • 总结

什么是 RPC

首先思考这样一个问题,假设你不知道任何框架,现在有两台机器,每台机器上有一个服务,让你在其中的一个服务中调用另一个服务中的接口,怎么样才能做到呢?

RPC 全称为远程过程调用(Remote Procedure Call Protocol),通俗点来说,就是从一台机器通过网络调用到另一台机器的某个方法。

那这样说来的话,通过 Socket 调用另一台机器的 Sokcet 服务也是RPC,通过一些 HTTP 请求工具包调用一个远程 HTTP 接口也是 RPC 了。

最开始的 RPC 定义还有可能是这样的,但是这种方式太底层、太繁琐了。

现在的 RPC 除了要有明显的网络通信特征外,还要具备下面几个特点:

  1. 良好的封装:让我们感觉调用远程接口就好像是调用本地方法一样方便,封装底层网络通信的细节,让我们更专注于业务逻辑。
  2. 良好的协议设计:数据在调用方和提供方传输,数据组织要遵循约定好的协议格式,比如 HTTP 协议、TCP 协议这种。
  3. 高效的序列化和反序列化:远程调用,所以很大一部分开销来自于数据传输,所以原则上数据量越小越好,这就依赖于序列化的算法了。

封装的艺术(如何隐藏底层逻辑)

如果每次调用提供方提供的方法时都像下面这样繁琐,指明 URL、自己构造 JSON 序列化字符串等等,会不会不太方便。

public static final MediaType JSON= MediaType.get("application/json; charset=utf-8");OkHttpClient client = new OkHttpClient();String post(String url, String json) throws IOException {RequestBody body = RequestBody.create(json, JSON);Request request = new Request.Builder().url(url).post(body).build();try (Response response = client.newCall(request).execute()) {return response.body().string();}
}

而像 Dubbo 这样调用,如果没有接触过 RPC 的人,刚看到这段代码会感觉到好像就是在调用本地的一个方法。隐藏了很多的细节。

@DubboReference
private DemoService demoService;String result = demoService.sayHello("world");
System.out.println("Receive result ======> " + result);

这就是现代 RPC 里一个很重要的特性,就是封装,尽量隐藏网络上的细节,让使用者感觉就是在调用本地的方法。
在这里插入图片描述

那在一般的 RPC 框架中,例如 Dubbo、GRPC等,是如何进行封装的呢。

我们看上面的图,其中调用方和服务提供方都有一个部分叫做存根(Stub),就是靠的它。听上去感觉这词不太容易理解啊,啥叫存根呢,其实说简单点儿就是一个代理方案。

举个例子,当我们调用本地的一个服务类的某个方法时,实际上这个服务类已经是一个代理类了,调用这个类的某个方法,实际上代理方法中可以加入很多额外的逻辑,比如构造 HTTP 请求、构造TCP 请求等等,最终穿过网络调用到真正的服务提供方的同名方法。

说到 Java 中的代理技术,相信大家都不陌生,有动态代理、静态代理,不了解的同学可以参考 Spring AOP 和 动态代理技术 这篇文章。

协议的实现

这里说的协议就是网络通信协议。远程过程调用嘛,那必须得通过网络传输才行,而通过网络传输那就得有遵行规定的协议。

这个协议是用来规范传输的数据的,所以它是一个应用层协议,比如 HTTP ,而不是传输层的协议,比如 TCP 、UDP 。

比如 GRPC 框架中用的协议是 HTTP2,Dubbo中可以选择多种协议,比如Hession、HTTP等。

下图是 HTTP 1.0 协议的格式,包括首部和请求内容,首部可以指定请求方式、URI、版本、内容类型和长度等,内容部分就是真正要传输的数据, 如果是一个 RPC 调用的话,那就是调用方法的参数和一些额外的信息(比如调用的方法名、类名等),首部和内容由一个空行分隔。

接收端可以根据空行了解哪些是头部,哪些是内容。

可以通过首部的内容长度字段来进行分配内存或其他操作。
在这里插入图片描述

其他的协议都有自己的格式,我们也可以自定义一个协议。如下是一个简单的协议格式:

通过魔术位可以直接判断是不是本协议数据,如果是的话,再进行处理。
通过整体长度和首部长度可以确定数据内容的长度,用来解析首部和数据。
通过序列化方式字段可以确定数据序列化采用的什么方式,用来实现反序列化。

0-8bit9-24bit25-32bit33-40bit
不定长标志位(魔术位)整体长度首部长度序列化方式

一个 RPC 框架使用哪种协议是有权衡取舍的,如果考虑通用性那就可能使用 HTTP或者 HTTP2这种协议,比如 GRPC ,这样一来,可以在各种语言框架中通用,但是性能就稍微差一点了。

而如果从性能方面考虑呢,那就要牺牲掉一部分通用性了,比如Hession、Dubbo2协议,只有框架开发者提供了对应语言的版本,才能在相应的语言中使用。

序列化和反序列化(编解码)

上面说的协议主要指的是数据通信协议,而序列化和反序列化其实也要遵循一定的协议。

说到序列化和反序列化,其实我们并不陌生。在Java开发中,经常会遇到。最常用的就是把 Java Bean 序列化为 JSON,将 JSON 反序列化为 Java Bean。

JSON 就是最常见的一种序列化和发序列化协议,其他的序列化方式还有 XML、GRPC 中用到的 Protocol Buffers。 Hessian 也有它自己的序列化算法。

为什么要有序列化呢,数据要想在网络中传输,那必须是二进制的形式。在远程调用里,我们像调用本地方法那样调用,使用的参数都是和当前项目语言一致的参数类型,比如Java中的 String、List、Map等等,那要把这些类型转换成二进制,靠的就是序列化算法。

JSON 和 XML 这种文本序列化方式比较简单,使用场景非常广泛,通用性强,但是序列化后产生的二进制体积也比较大,这样在传输的时候就会比较耗时、占用带宽。

而像 Protocol Buffers 这种序列化方式,它使用结构化的消息定义语言(IDL)来定义数据结构和服务接口,支持多种编程语言,而且序列化后的二进制也会最大程度的压缩,少占用带宽,有很高的传输效率。

总结

下图是整个 RPC 调用过程的简化版。
在这里插入图片描述

序列化和反序列化功能会在代理中进行,在很多框架中也称这部分为编解码。

封装的网络请求既有可能是 HTTP 请求,也有可能是 Sockets 请求,比如有很多 RPC 功能都使用 Netty 作为通讯层。

除了主要的功能外,一个成熟的 RPC 框架还有考虑诸多其他因素,比如性能、安全性、兼容性等等。

相关文章:

RPC框架的核心是什么

文章目录 什么是 RPC封装的艺术(如何隐藏底层逻辑)协议的实现序列化和反序列化(编解码)总结 什么是 RPC 首先思考这样一个问题,假设你不知道任何框架,现在有两台机器,每台机器上有一个服务&…...

直播、AI赋能,美团披着荆棘前行

随着互联网流量红利逐渐消退,阿里、抖音、腾讯、拼多多、快手、小红书等各赛道玩家,为了寻求新的增量,纷纷“卷”向本地生活,开始入侵美团的腹地。然而,哪怕巨头环伺,美团仍然展现出了其独特的竞争力&#…...

提升代码逻辑的感觉——python循环语句

提升代码逻辑的感觉——python循环语句 简介 循环是编程中的一个非常重要的概念,它用于处理重复性任何和迭代草错,通过循环我们能优化并简化代码,提高代码的可维护性,在Python中循环是一种控制结构,允许我们重复执行…...

【ARM Coresight 系列文章 20 -- linux perf 与 ARM coresight】

文章目录 1.1 Perf Introduction1.1.1 Perf 架构图1.1.2 Perf Tools 介绍1.1.3 Perf 命令介绍1.2 Events1.2.1 Perf 与 PMU 的关系1.2.2 Hardware events1.2.1.1 linux perf 事件分类1.2.2 Software Events1.2.3 Tracepoint Events1.3 Perf 工具使用1.4 用户态开发1.4.1 用户态…...

微服务之Nacos

1 版本说明 官网地址: https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 1.1 2021.x 分支 适配 SpringBoot 2.4, Spring Cloud 2021.x 版本及以上的Spring Cloud Alibaba 版本如下表(最新版本用*标记&am…...

jvm 新生代的区域划分

虚拟机将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次分配内存只使用 Eden 和其中一块 Survivor。发生垃圾收集时,将 Eden 和 Survivor 中仍然存活的对象一次性复制到另外一块 Survivor 空间上,然后直接清理掉 Eden 和已用过…...

【C++】对于string的补充(成员函数c_str()、大小写转换、字符串和实数之间的相互转换)

前言 本篇文章记录的是一些关于string的补充说明 string与const char*之间的相互转换 const char* 转换成string 在C中存在着从const char到string的隐式类型转换,换句话说,如果一个函数的参数类型是string类,直接传入const char类型的参…...

华为OD机试真题【羊狼农夫过河】

1、题目描述 【羊、狼、农夫过河】 羊、狼、农夫都在岸边,当羊的数量小于狼的数量时,狼会攻击羊,农夫则会损失羊。农夫有一艘容量固定的船,能够承载固定数量的动物。要求求出不损失羊情况下将全部羊和狼运到对岸需要的最小次数。…...

【线性代数-3Blue1Brown】- 5 三维空间的线性变换

飞书原文档:Docs...

Maven入门教程(二):idea/Eclipse使用Maven

Maven入门教程(一):安装Maven环境 4.开发工具配置 4.1 idea配置 idea有多个版本,配置是一样的,只是配置页面的入口不一样 旧版idea 新版idea 4.2 Eclipse配置 打开Eclipse,菜单中选择:Window -> Preference ->…...

【MySQL】MySQL里的用户账户和角色是什么?如何管理?

用户(user)验证和授权创建用户账户连接服务器查看用户账户设置 角色(role)创建角色 操作用户帐户和角色重命名删除 感谢 💖 用户(user) 在MySQL中,用户是数据库访问的主要实体。每个…...

vbs病毒

vbs脚本:VBS脚本病毒原理分析和防范 疯狂代码 http://CrazyCoder.cn/ Sh t t p : / C r a z y C o d e r . c n / S e c u r i t y / Ar t i c l e 7 2 0 0 8 . h t m l 网络流行让我们世界变得更加美好但它也有让人不愉快时候当您收到封主题为1LoveYou” 邮件用兴奋 得几乎快发…...

用Java实现Huffman编码

文章目录 前言一、实现思路二、准备Huffman结点三、主要实现 前言 在使用http1.1协议传输数据的时候,会有一些固定的字段,比如cookie、编码方式、接收的数据类型,另外会有一些大量重复的字段造成请求报文过于冗长,为了解决这个问…...

day-04 基于UDP的服务器端/客户端

一.理解UDP (一)UDP套接字的特点 UDP套接字具有以下特点: 无连接性:UDP是一种无连接的协议,这意味着在发送数据之前,不需要在发送方和接收方之间建立连接。每个UDP数据包都是独立的,它们可以独…...

FFmpeg rtp rtp_mpegts的区别

rtp 在FFmpeg中,rtpenc是一个用于将音视频数据封装成RTP(Real-time Transport Protocol)数据包并发送到网络上的编码器。RTP是一种用于实时传输音视频数据的协议,常用于视频会议、流媒体等场景。 rtpenc可以将音视频数据封装成R…...

【链表OJ】相交链表 环形链表1

前言: 💥🎈个人主页:​​​​​​Dream_Chaser~ 🎈💥 ✨✨刷题专栏:http://t.csdn.cn/UlvTc ⛳⛳本篇内容:力扣上链表OJ题目 目录 一.leetcode 160. 相交链表 1.问题描述: 2.解题思路: 二.leetcode 141.环形链表 …...

DevOps之自动化测试

什么是自动化测试? 明确一下自动化测试不是什么。自动化测试不是指自动化生成测试代码,而是自动化地执行由开发人员或测试人员编写的测试代码。正如下面这句谚语:“绝不要手工去做任何可以被自动化处理的事情。——Curt Hibbs” 之前是由人…...

Java 程序打印 OpenCV 的版本

我们可以使用 Java 程序来使用 OpenCV。 OpenCV 的使用需要动态库的加载才可以。 加载动态库 到 OpenCV 的官方网站上下载最新的发布版本。 Windows 下载的是一个可执行文件,没关系,这个可执行文件是一个自解压程序。 当你运行以后会提示你进行解压。…...

ChatGPT⼊门到精通(2):ChatGPT 能为我们做什么

⼀、雇佣免费的⼲活⼩弟 有了ChatGPT后,就好⽐你有了好⼏个帮你免费打⼯的「⼩弟」,他们可以帮你做很多 ⼯作。我简单总结⼀些我⽬前使⽤过的⽐较好的基于ChatGPT的服务和应⽤。 1、总结、分析 当我们在阅读⼀些⽂章和新闻的时候,有的⽂章写…...

线程和进程的区别是什么?

线程(Thread)和进程(Process)是操作系统中两个重要的概念,用于管理程序的执行。它们有以下区别: 定义:进程:进程是程序的一个执行实例,它包含了程序的代码、数据以及执行上下文。进程是操作系统分配资源和调度的基本单位。线程:线程是进程的子执行单元,一个进程可以…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

【C++进阶篇】智能指针

C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...