[Java] 浅析rpc的原理及所用到的基本底层技术

news2024/11/19 6:38:28

文章目录

  • 前言
  • 阅读前须知
  • rpc是什么?
    • 别的进程 vs 别的机器
  • rpc的目的或是我们为什么需要rpc?
  • 实现rpc所涉及到的底层技术
    • 1. 通信技术(网络IO、Network IO)
      • 套接字(Socket)
      • bio、nio与Netty
    • 2. 网络协议(字节数据解析技术)
      • 固定长解析(Fixed Length)
      • 编码与解码
      • 序列化与反序列化技术(Serialization & Deserialization)
  • rpc调用时需要传递的核心信息
  • 结语

前言


在企业级系统架构的发展过程中,把单一应用做拆分是一个大趋势。单一应用我们可以理解其为单个进程,单一应用架构在应用体量变得庞大时会面临难以维护、依赖项过多、性能低劣等问题,把单一应用里从属不同领域的服务拆分到别的应用中变得非常有必要。无论是竖向的按产品拆分还是横向的根据职责拆分都会拆分出多个小应用(这些也都是进程)。那么简单理解rpc的话,就是在横向拆分时出现的一个需求。本文将围绕rpc的基本需求去浅析rpc的原理

阅读前须知


本文旨在帮助读者建立对rpc的基本认知,不会从现有商业rpc产品的源码角度去具体分析他们的实现。通过阅读本文你会对以下概念有一些基本认知。

  • rpc
  • 网络协议
  • 套接字
  • bio、nio、Netty
  • 编码与解码
  • 序列化与反序列化

rpc是什么?


要理解rpc,首先我们需要知道rpc到底是个什么玩意儿,那么rpc到底是什么呢?
rpc,全称remote procedure call,中译为远程过程调用。用白话来讲就是在别的进程上执行计算任务,因为不在当前进程上执行,是为远程

别的进程 vs 别的机器

需要注意的是有一个常见的误区,这里提到的是别的进程并不是别的机器,这意味着你可以在同一台机器上同时部署rpc服务消费者和rpc服务提供者,当然一般生产环境中还是以调用其他机器上的进程为主

rpc的目的或是我们为什么需要rpc?

我们知道了rpc是什么之后,我们还需要知道为什么要用rpc?在前言部分我们也提到了rpc出现是因为业务系统的横向切分导致的。什么意思呢?

设想我们有一个基于http协议的Restful API服务器,我们收到来自外部客户端的请求通常需要经过几层

  1. tomcat之类的服务器组件接收外部连接和数据(字节数组byte[]),解析并包装为如J2EE标准的调用
  2. spring web之类的网络应用框架负责接受J2EE标准的调用,并通过如适配器adapter、分发器等内部组件分发和适配J2EE请求到咱们开发者写的@Controller类的各类方法里。
  3. 咱开发者编写的@Controller类的各类方法接收到请求后,需要去根据业务需求去调用不同的@Service去完成任务。
  4. @Service服务层接受到请求后去@repository数据访问层请求数据和做一些运算。
  5. @Repository数据访问层去如redis缓存、关系型数据库、elastic search服务去存取数据。

那么如果我们把@Service的计算任务交给另一个进程去做,我们的应用就变成两个应用,具体表现是两个进程。
一个进程对外提供http restful api服务,另一个进程提供数据的计算服务。为了能让这两个进程能够协同工作,就需要rpc技术了。

实现rpc所涉及到的底层技术

rpc是相对比较高层或中层的一个概念,要实现rpc需要一些偏底层的技术。这些底层技术都是些什么呢?

1. 通信技术(网络IO、Network IO)

文章读到这里,不难发现我们的rpc需要是在不同进程、特别是不同物理服务器的不同进程之间需要做数据交流(即:通信,那么毫无疑问需要涉及到通信相关技术。我们这里不谈定位机器的IP协议、路由器、私有网络、DNS域名寻址服务等更底层的东西,我们谈应用级别通信技术:套接字(Socket)

套接字(Socket)

套接字这个翻译说实话并不利于中国人理解,笔者在这里明确一点Socket套接字其本质是一个文件,外部Client端给某个Socket传递数据本质就是向这个文件写入数据,那我们的Server端再从Socket文件取数据这就是我们网络IO数据传输的一个本质。socket文件里数据的读写功能是由OS提供的。那么既然Socket本质是文件,打开很多套接字(即:建立多个连接) 会有问题吗?

答案是会有问题,在一些Linux操作系统默认配置下一个进程可以打开的文件数量是有上限的,一般是1024个。
所以如果打开太多的文件就会遇到“open too many files”错误,这个错误可以通过修改操作系统配置去解决。
读者可以自行搜索如何解决,笔者这里只是简单提一下。国内随便百万级别并发的话,1024个实在是太少了,几万都不够看的。
然后因为如TCP、UDP协议的限制,只有16个bit用于表示端口信息,所以一个机器的端口数量最多为2^16(65536个),
也就是一个机器的总并发连接数量其实被限制在了几万,所以如果To C应用不做集群几乎不可能满足国内这么大的并发连接需求。

bio、nio与Netty

前面我们提到了套接字本质是文件,那么我们应用程序要接受外部的数据的任务就变成了从Socket文件里里读取数据。那么从文件里读数据呢,操作系统就提供了很多种方式有:

  • bio(blocking io):读数据的线程会被阻塞直到数据读取完毕,也就是Socket文件直到外部写入到读取完成为止会阻塞我们的工作线程。
  • nio(non-blocking io):读数据时不再阻塞,而是首先询问操作系统有哪些Socket文件准备好数据读取了,然后针对这些准备就绪的文件利用bio进行一个读取。其IO模型被称为多路复用IO模型。
  • aio(async io):异步io目前还不成熟且用得比较少本文不谈。

关于bio,假设你需要从10000个socket文件里读取数据(1万的并发),如果运气不好,我们开的假设16个工作线程去读的Socket文件,每次都等了很久数据才准备就绪(数据是来自外部,从网卡来的),那么你的应用整体大部分时间都处在等待的一个状态,这是非常低效的

关于nio,还是上面的1万并发的例子,你只需要一个线程就能满足向操作系统轮询哪些Socket文件准备就绪的任务。比如你某次询问,OS回答有177个Socket文件准备好读写了,这时这个线程再派发这177个Socket文件的读写任务到工作线程,这相比仅利用bio的方式就根本没有工作线程等待io过程。需要注意这些工作线程读取Socket文件的方式依然是bio的,速度大幅加快的原因是因为没有等待的这个过程。nio也是目前可以说所有的分布式框架、应用都用到的技术。

关于Netty,操作系统提供了bio、nio的支持,开发者需要使用的话还需要语言层面的支持,比如Java JDK的java.nio包里的Selector之类的,而JDK中nio相关的API学习成本高及难以使用是一个问题,所以Netty出现了,Netty底层使用nio,对其使用者封装了一些便利好用的接口方便Java开发者去进行网络编程。选择Netty来进行网络编程的话无非就是会引入额外的Netty依赖,所以如Tomcat服务器就没有使用Netty而是直接使用nio,而如dubbo呢就是用的Netty。

2. 网络协议(字节数据解析技术)

通过上面的通信技术,我们已经能够在应用内拿到请求原始数据(字节数组byte[])了,把这些字节恢复成或者说转换成我们一个开发者可用的数据结构(Java对象、Java原生类型等)就是网络协议的主要任务之一了。通常解析字节数组我们有很多种方式。

固定长解析(Fixed Length)

固定长解析,或者说固定格式解析,这种方式通常被用来解析协议头(byte[]数据里最开头的部分)。协议设计者为了减小协议数据包的大小,通常存储信息最小单位是按bit来的,这种解析方式里位运算会使用得相对较多。

比方说我们可以看一下TCP头长什么样。在下图中可以看到第一行4字节(32位)数据,前16位是Source Port,后16位是Destination Port。顺带一提因为用来存储端口信息的数据位只有16位,这也是为什么端口数量至多是2^16(65536)个的原因。

TCP Header

编码与解码

编码解码,比较常见的应用场景是字符串和字节数组互相转换。当然不限于此,比如流媒体领域也有非常多的编码解码,字符串编码解码通常是如下的一个处理过程:

  • 编码:encode(String) → byte[],把字符串转换成字节数组;
  • 解码:decode(byte[]) → String,把字节数组恢复成字符串;

常见的字符串编码解码方式:

  • 万国码utf系列的如utf8、utf16等;
  • 日本的jis、shift-jis系列;
  • 中国的国标GB系列;

大家接触最多的可能就是http协议中body如果是json字符串,那么其编码方式在rfc中被规定为了utf8,也就是说如果你来开发http服务器/客户端 组件,你在http头里看到数据是json时,用utf8解码就可以获得json格式的字符串了。当然如果你还想要获取json格式字符串里面具体的数据,那么你需要做文本解析,各类XX Language都有的语法解析器那一套了,本文不谈论这个。

序列化与反序列化技术(Serialization & Deserialization)

那么其实呢序列化与反序列化与编码与解码非常类似的概念,你甚至可以把编码理解为字符串对象的序列化。序列化通常指的是在OOP语言中,把某一对象实例转换成byte[]用于网络传输或持久化到硬盘里。反序列化则是其逆向操作,把byte[]在别处恢复成对象实例。

  • serialize(obj) → byte[],把对象转换成字节数组;
  • deserialize(byte[]) → obj,从字节数组中恢复对象;

rpc调用时需要传递的核心信息

我们了解了实现rpc的一些技术手段之后,就是需要思考我们在实现rpc过程中需要在rpc服务消费者(调用方)和rpc服务提供者(被调用方)之间传递什么样的数据了。

这个其实很好想到,无非就是调用方需要告诉被调用方我到底要调用哪个接口哪个方法调用参数等信息。那么被调用方完成计算任务后需要返回结果,这里面无非是一些被序列化的数据或是被序列化的Exception异常信息。

  • 调用方 → 被调用方:{“方法”: “java.lang.String#equals(String)”, “参数”: “abccc”, “实例名”: “xxxObj”}
  • 被调用方 → 调用方:{“调用结果”: 成功, “结果”: true} 或是异常 {“调用结果”: “异常”, “异常”: “java.lang.NullPointerException”}

笔者这里为了方便大家看是用了JSON格式字符串来作为信息的载体,但是呢字符串编码的方式会有数据包较大和二次解析(byte[]到String再到Obj)的一个问题,通常主流rpc框架会选用序列化而不是字符串编码的方式来传递数据。

其实有了上面的rpc核心信息和实现rpc的底层技术的概念之后我们就能实现一个自己的简单版rpc工具了。

结语


本文没有讨论任何市面上主流rpc框架的具体实现,仅仅讨论了rpc的概念、rpc实际的运作原理和其所需的核心信息。通过本文笔者希望我们大家都能理解rpc的本质到底是什么,这样无论是面对阿帕奇的dubbo、谷歌的gRPC亦或是老旧的SOAP,咱们都能快速的理解其到底是在干什么。
商业产品无穷无尽,唯有理解其本质才能以不变应万变。我是虎猫,希望本文能帮到你。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【仿真建模】第三课:AnyLogic入门基础课程 - 多层建筑行人疏散仿真讲解

文章目录一、Agent类的概念二、行人疏散仿真2.1 仿真模型示意图2.2 具体实现步骤一、Agent类的概念 二、行人疏散仿真 2.1 仿真模型示意图 2.2 具体实现步骤 首先,新建模型 新建一个MyFloor1对象,代表第一个楼层 创建矩形墙,并放到原点…

专业数采软件DXP OPC Server售后问题解决方案

DeviceXPlorer OPC Server是一套实现工业自动化设备数据读取或发送的软件。它提供与制造车间中的控制设备(如 PLC、机床和机器人)的连接,支持200多种设备通讯协议,便捷的配置,快速实现设备联网采集。 在与设备通讯方面…

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计

🎀 精彩专栏推荐👇🏻👇🏻👇🏻 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业…

idea永久设置maven配置,新项目不用再设置

在这里设置就是永久的设置,新项目将使用该设置,maven的配置也在新项目和新模块创建的时候直接加载 英文的话,看位置大概也应该可以找到 点开后左上角搜索maven,找到如图maven的设置 主路径就是maven的安装包软件的路径 用户设置…

LeetCode 110平衡二叉树 257.二叉树的所有路径 404左叶子之和

文章目录110平衡二叉树c 代码实现python 代码实现257.二叉树的所有路径c代码实现python 代码实现404左叶子之和c 代码实现python 代码110平衡二叉树 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡二叉树定义为: 一个…

http 知识整理

1. 启发式缓存 在不设置cache-control/expires的情况下,浏览器不会默认进入协商缓存。而是根据Date/LastModified去自动计算出合适的缓存时间。 计算方式为:(Date - LastModified) * n n:LM-Factor,处于[0,1]之间 2. 强制缓存 -…

Vue的模版代码与数据绑定方式

目录 模版代码 插值语法 指令语法 数据多层访问 vue模版语小结 数据绑定方式 模版代码 插值语法 插值语法就是使用{{xxx}}描述的 <div id"root">{{name}} </div> 指令语法 <div id"root"><a :href"school.url">…

lazada买家订单导出

下载安装与运行 https://www.yuque.com/webcrawl/handbook/mtad3q 用途与功能 所见即所得的导出自由选择导出项支持Excel、JSON两种方式导出自由排序Excel导出列顺序导出过程中有进度提示&#xff0c;用户可以随时提前中止 导出过程演示 选择lazada订单导出&#xff0c;开始…

linux内核整体架构

操作系统概念 操作系统属于软件范畴&#xff0c;负责管理系统的硬件资源。OS具备的功能&#xff1a;1.为应用程序提供执行环境。2.为多用户和应用程序管理计算机的硬件资源。3.虚拟化功能。4.支持并发。 宏内核与微内核架构 宏内核&#xff1a;所有的内核代码都编译成二进制…

基于JAVA的学生课程后台管理系统【数据库设计、源码、开题报告】

数据库脚本下载地址&#xff1a; https://download.csdn.net/download/itrjxxs_com/86427641 开学选好课是具备学术能力的首要表现。学生不能为了拿高分&#xff0c;只选简单课程&#xff0c;也没有必要为了显示出自己热衷自我挑战&#xff0c;奋不顾身地一头扎进高难度课程。在…

强化深度学习中利用时序差分法中的Sarsa算法解决风险投资问题实战(附源码 超详细必看)

需要源码请点赞关注收藏后评论区留下QQ~~~ 一、Sarsa算法简介 Sarsa算法每次更新都需要获取五元组&#xff08;S,A,R,S,A&#xff09;这也是该算法称为Sarsa的原因&#xff0c;每当从非终止状态进行一次转移后&#xff0c;就进行一次更新&#xff0c;但需要注意的是&#xff0…

【论文阅读】社交网络传播最大化问题-04

Efficient Influence Maximization in Social Networks相关工作改进的贪心算法对独立级联模型的改进对加权级联模型的改进改进度折扣算法影响力最大化&#xff1a;在社交网络中找到一小部分能够最大化传播影响力的节点(种子节点)。一是改进原有的贪心算法&#xff0c;进一步缩短…

KMP算法——通俗易懂讲好KMP算法:实例图解分析+详细代码注解

文章目录1.kmp算法基本介绍2.字符串的最长公共前后缀&部分匹配表2.1 什么是最长公共前后缀2.2 什么是部分匹配表Next2.3 字符串最长公共前后缀&部分匹配表的代码实现2.4 代码测试3.根据部分匹配表搜索字符串匹配位置3.1 匹配成功一个就退出匹配的代码3.1.1 KMP算法的大…

Vue父组件给子组件传参数

别人在调用我们写的组件时&#xff0c;虽然要实现的结构一样&#xff0c;但如果别人想改一下显示的内容或者之类的&#xff0c;该怎么做呢&#xff1b;这时候就要提到“传参数”这个词了&#xff0c;别人可以通过传不同的参数&#xff0c;来实现他们具体的结构&#xff1b; 传参…

SpringBoot SpringBoot 开发实用篇 5 整合第三方技术 5.22 RabbitMQ 安装

SpringBoot 【黑马程序员SpringBoot2全套视频教程&#xff0c;springboot零基础到项目实战&#xff08;spring boot2完整版&#xff09;】 SpringBoot 开发实用篇 文章目录SpringBootSpringBoot 开发实用篇5 整合第三方技术5.22 RabbitMQ 安装5.22.1 Erlang下载5.22.2 安装5.…

HTML+CSS期末大作业 中国传统美食网站设计 节日美食13页 html5网页设计作业代码 html制作网页案例代码 html大作业网页代码

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

3招学会TikTok电商选品,速看

Sensor Tower商店情报数据显示&#xff0c;2022年10月Instagram以将近6700万下载量&#xff0c;成为全球移动应用&#xff08;非游戏&#xff09;下载榜冠军&#xff0c;较2021年10月增长17.2%。其中&#xff0c;印度市场的下载量占45.2%&#xff0c;美国市场的下载量占比为5.4…

《码出高效:Java开发手册》笔记之二-面向对象

前言 第二章主要是讲面向对象&#xff0c;也就是oop&#xff0c;这个概念其实很多人已经听腻了&#xff0c;都是非常基础的知识&#xff0c;本章就是讲一些java以及很多编程语言的基础设计思想 正文 oop理念 面向对象是在早期滥用面向过程编程后出现的&#xff0c;面向过程…

CSS清除浮动的五种方法(超详细)

1.为什么要清除浮动? 浮动的原理是让图片脱离文档流&#xff0c;直接浮在桌面上。我们一般布局的时候都是只设置宽度不设置高度&#xff0c;让内容来自动填充高度。但使用浮动后会让原本填充的高度消失&#xff0c;父元素高度为0&#xff0c;后续添加内容布局会产生混乱,造成…

C语言tips-数组指针和指针数组

最近因为工作需要开始重新学c语言&#xff0c;越学越发现c语言深不可测&#xff0c;当初用python轻轻松松处理的一些数据&#xff0c;但是c语言写起来却异常的复杂&#xff0c;这个板块就记录一下我的c语言复习之路 数组指针 概念&#xff1a;顾名思义就是一个指针&#xff0c;…