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

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子&#xff08…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

2025季度云服务器排行榜

在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...