Netty源码 之 ByteBuf自适应扩缩容源码

news2024/10/7 12:18:09

Netty体系如何使得ByteBuf根据实际IO收发数据场景进行自适应扩容缩容的?

IO收发数据的过程:

read 读取("I"):网卡硬件通过网络传输介质读取对端传输过来的数据,网卡硬件再把数据写到recv-socket缓冲区,应用程序编写逻辑把recv-socket缓冲区的数据读取到ByteBuf。

write 写出("O"): 应用程序写到ByteBuf,ByteBuf的数据再flush刷新到send-socket缓冲区,send-socket再把数据写到网卡硬件,网卡硬件通过网络传输介质传输给对端。

像之前我们使用Netty进行开发时,最寻常的方式是如何申请一个ByteBuf空间?

ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();

但是这样申请ByteBuf空间具有一个弊端:ByteBuf是固定空间大小的,导致收发socket缓冲区的数据时,ByteBuf可能过大或过小,如果Netty体系可以封装一种方法逻辑去使得ByteBuf自适应的扩容缩容,那么可以最大程度的利用ByteBuf 并且最大利用的提升IO收发数据的性能。

Netty是怎么做的?

是由如下AbstractNioByteChannel类中核心逻辑链路read方法:

  • 开始分析

1.Netty封装了一个自适应实际场景变化大小的ByteBuf,比原生直接通过ByteBufAllocator.allocate()创建ByteBuf要灵活的多。原生创建ByteBuf的方式导致ByteBuf的大小固定不可变。

2.

为什么IO基本上都是使用直接内存?

因为对于IO这种强阻塞,高数据量的传输操作,其实使用直接内存的目的就是为了减少数据的拷贝,实现零拷贝。IO收发数据量过大,使用直接内存可以极大的减少数据的拷贝次数。

如何申请直接内存?通过Unsafe。

Unsafe:跳过JVM虚拟机,直接操控操作系统所管理的内存资源。

原来:java--->JVM--->OS--->计算机内存

引入Unsafe后:java(Unsafe)--->OS--->计算机内存

直接内存的创建,其实底层就是使用Unsafe这个类去直接向操作系统申请了一块内存。

非直接内存其实就是堆内存,也就是向JVM申请的堆内存。JVM通过自身的C++程序再向OS操作系统去申请真正的内存空间。这样性能就差了很多。

JUC的CAS很多类底层都是Unsafe做的,所以性能高。比如说:AtomicInteger

3.

4.guess()方法,返回nextReceiveBufferSize。该属性值代表当前我们应该把ByteBuf缓冲区的大小设置成nextReceiveBufferSize大小。该值的大小是通过上一次ByteBuf的读取情况进行动态变化的,具体是如何进行自适应变化得出的?后续慢慢分析。

5.

6.doReadBytes方法

recvBufAllocatorHandle()

7.

8.static静态代码块中的代码会执行加载一次

分析static静态代码块的代码逻辑:

ByteBuf自适应扩容池sizeTable中有许多ByteBuf可选的值大小,但是sizeTable中的数据值是具有一定规律的,规律如下:

1.当可选值大小小于512时,从16开始递增,每次递增16,把每一个可选值加入到sizeTable中。在第一个for循环结束后,sizeTable这一自适应扩容池中有可选值:16,32,48,64,80,96,112,.........,512

2.当可选值达到512,且不超过int整型最大值【不包含int整型最大值】的范围之间,可选值按照2倍的大小进行递增。所以在第二个for循环结束后,sizeTable这一自适应扩容池中有可选值:16,..........,512,1024,2048,.........,Integer.MAX_VALUE / 2

当sizeTable集合初始化完成后,创建SIZE_TABLE数组,把集合中的所有元素都放入到SIZE_TABLE数组中。

9.传入一个size,在扩容池SIZE_TABLE中找到一个与size最相近的可选值,并且返回该可选值所对应的索引下标。查找利用的是二分查找法。

10.

11.前面的准备工作,属性初始化工作都做完后,这里展开分析record自适应扩缩容ByteBuf的核心逻辑:

分支1:INDEX_DECREMENT=1,为递减频率。

max(0,index-INDEX_DECREMENT):二者找到一个最大值。意思就是最小递减到0

SIZE_TABLE[max(0,index-INDEX_DECREMENT)]:表示最低递减到可选值为16的ByteBuf,也就是索引值为0所对应的元素值

如果actualReadBytes(实际要从socket缓冲区读取到ByteBuf的数据大小) 小于等于 SIZE_TABLE[max(0,index-INDEX_DECREMENT)],说明可以自适应缩容。你思考一下,你都往前找一个可选值了,结果实际读取的ByteBuf数据大小还是小于等于该已经假设递减过的数据值了,那么说明当前ByteBuf在往前缩小一个后还是使用不完全,那么你是不是可以把ByteBuf缩小到该假设递减到的大小。

但是Netty这里又做了一层逻辑,兜底,第一次判断为true后,由于decreaseNow=false,不会真正的缩容。但是当第二次读取又一次进入该record方法时,还是判断出if为true,那么又一次说明真的用不完,那么因为此时decrease=true,所以可以进入内层if分支,那么可以真正的执行缩容逻辑,并且把decreaseNow置为false。eg:把32执行一次这个缩容逻辑,最终变为16

分支2:INDEX_INCREMENT=4

如果actualReadBytes(实际要从socket缓冲区读取到ByteBuf的数据大小) 大于或等于当前ByteBuf的大小时,我们需要进行扩容操作。扩容时是按照频率INDEX_INCREMENT=4进行扩容,也就是每次向后跳四个可选值的频率进行递增。但是ByteBuf最大值不可以超过Integer.MAX_VALUE/2。同理会做很多处理逻辑。eg:把16执行一遍这个扩容逻辑,最终变为80

并且把decreaseNow置为false。

12.

所以:

这一轮我们通过record方法可能设置出的nextReceiveBufferSize的变量值大小,最终下一次do while再循环到调用allocate方法时,其中调用ioBuffer方法申请大小时,参数使用的guess()方法就会使用到上一次设置的nextReceiveBufferSize的值大小。

13.至此,Netty构建的ByteBuf的扩容缩容机制也就分析结束了。

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

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

相关文章

OpenShift 4 - 在 OpenShift 上运行物体检测 AI/ML 应用

《OpenShift / RHEL / DevSecOps 汇总目录》 说明:本文已经在 OpenShift 4.14 RHODS 2.5.0 的环境中验证 说明:请先根据《OpenShift 4 - 部署 OpenShift AI 环境,运行 AI/ML 应用(视频)》一文完成 OpenShift AI 环境…

C语言--------指针(1)

0.指针&指针变量 32位平台,指针变量是4个字节(32bit/84)--------x86 64位平台,指针变量是8个字节(64bit/88)--------x64 编号指针地址;我们平常讲的p是指针就是说p是一个指针变量; ************只要…

Android13开发者模式的无线调试

设备: 三星GalaxyA13android13mac 重点介绍:无线调试 无线调试,又称为“无线ADB调试”,它可以在不用数据线连接的情况下,通过无线网络连接电脑进行调试和开发工作。以下是具体的使用步骤: 前提&#xff…

Transformers微调BERT模型实现文本分类任务(colab)

1. 数据准备 使用colab进行实验 左上角上传数据,到当前实验室 右上角设置GPU选择 查看GPU ! nvidia-sm安装需要的库 !pip install datasets !pip install transformers[torch] !pip install torchkeras1.1 读取数据 import pandas as pd data pd.read_csv(&…

thinkphp6入门(19)-- 中间件向控制器传参

可以通过给请求对象赋值的方式传参给控制器&#xff08;或者其它地方&#xff09;&#xff0c;例如 <?phpnamespace app\middleware;class Hello {public function handle($request, \Closure $next){$request->hello ThinkPHP;return $next($request);} } 然后在控制…

Android7.0-Fiddler证书问题

一、将Fiddler的证书导出到电脑&#xff0c;点击Tools -> Options -> HTTPS -> Actions -> Export Root Certificate to Desktop 二、下载Window版openssl&#xff0c; 点击这里打开页面&#xff0c;下拉到下面&#xff0c;选择最上面的64位EXE点击下载安装即可 安…

第十五篇【传奇开心果系列】Python的OpenCV库技术点案例示例:图像配准

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例系列短博文目录前言一、常见的图像配准任务介绍二、图像配准任务:图像拼接介绍和示例代码三、图像配准任务:图像校正介绍和示例代码四、图像配准任务:图像配准介绍和示例代码五、基于特征点的配准方法介绍…

typecho 在文章中添加 bilibili 视频

一、获取视频来源&#xff1a; 可以有2种方式来定位一个 bilibili 视频&#xff1a; 第一种是使用 bvid 参数定位第二种是使用 aid 参数定位 如何获取这两个参数&#xff1f; 首先我们可以看看 bilibili 网站中的视频页面链接其实可以分为两种&#xff1a; 第一种是类似&a…

自动化测试 —— Web自动化三大报错

Web自动化三大报错有哪些呢&#xff1f;接下来给大家讲讲。 Web自动化三大报错&#xff08;Exception&#xff09; 1. Exception1&#xff1a;no such element&#xff08;没有在页面上找到这个元素&#xff09; reason1&#xff1a;元素延迟加载了 solution&#xff1a; …

手把手教你激活BetterZip for Mac免费下载(附注册码) v5.3.4

软件介绍 BetterZip for Mac是一款广受欢迎的文件解压缩工具&#xff0c;支持Mac以及Windows等多个平台&#xff0c;能够生成被Win和Mac支持的压缩包&#xff0c;让用户可以在Mac和Windows电脑之间使用一种通用压缩包&#xff0c;用户可以更快捷地向压缩文件中添加和删除文件&…

设计模式-行为型模式(下)

1.访问者模式 访问者模式在实际开发中使用的非常少,因为它比较难以实现并且应用该模式肯能会导致代码的可读性变差,可维护性变差,在没有特别必要的情况下,不建议使用访问者模式. 访问者模式(Visitor Pattern) 的原始定义是&#xff1a; 允许在运行时将一个或多个操作应用于一…

有哪些方法可以配置并发服务器?

通过合理配置并发服务器&#xff0c;可以提高服务器的处理能力和响应速度&#xff0c;从而更好地满足用户需求。本文将介绍一些常见的并发服务器配置方法&#xff0c;以帮助您更好地实现服务器的高效运行。 一、选择合适的操作系统 操作系统的选择是并发服务器配置的重要环节…

泛娱乐社交出海洞察,Flat Ads解锁海外增长新思路

摘要:解读泛娱乐社交应用出海现状与趋势,解锁“掘金”泛娱乐社交出海赛道新思路。 根据全球舆情监测机构 Meltwater 和社交媒体机构We are Social最新发布数据显示,全球社交媒体活跃用户数量已突破50亿,约占世界人口总数62.5%。庞大的用户数量意味着广阔的增量空间,目前,随着全…

【NLP 自然语言处理(一)---词向量】

文章目录 什么是NLP自然语言处理发展历程自然语言处理模型模型能识别单词的方法词向量分词 一个向量vector表示一个词词向量的表示-one-hot多维词嵌入word embeding词向量的训练方法 CBOW Skip-gram词嵌入的理论依据 一个vector&#xff08;向量&#xff09;表示短语或者文章ve…

力扣精选算法100道——和为 K 的子数组[前缀和专题]

和为K的子数组链接 目录 第一步&#xff1a;了解题意​编辑 第二步&#xff1a;算法原理 第三步&#xff1a;代码 第一步&#xff1a;了解题意 数组中和为k的连续子数组&#xff0c;我们主要关注的是连续的&#xff0c; 比如[1,1,1],和为2的子数组有俩个&#xff0c;比如第…

Springboot简单设计两级缓存

两级缓存相比单纯使用远程缓存&#xff0c;具有什么优势呢&#xff1f; 本地缓存基于本地环境的内存&#xff0c;访问速度非常快&#xff0c;对于一些变更频率低、实时性要求低的数据&#xff0c;可以放在本地缓存中&#xff0c;提升访问速度 使用本地缓存能够减少和Redis类的远…

JWT令牌 | 一个区别于cookie/session的更安全的校验技术

目录 1、简介 2、组成成分 3、应用场景 4、生成和校验 5、登录下发令牌 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发、数据结构和算法&#xff0c;初步涉猎Pyth…

波纹扩散效果

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>波纹扩散</title><style>body {disp…

在 vite + ts 中,使用require

因为 require 属于 Webpack 的方法&#xff0c;所以 Vite 项目中是不能使用require的&#xff0c;所以控制台会给你报错&#xff0c;如下 解决办法如下&#xff1a;就是很不情愿的办法&#xff0c;没招啊 第一步、安装插件 npm i vite-plugin-require-transform --save-de…

【蓝桥杯冲冲冲】[NOIP2017 提高组] 宝藏

蓝桥杯备赛 | 洛谷做题打卡day29 文章目录 蓝桥杯备赛 | 洛谷做题打卡day29[NOIP2017 提高组] 宝藏题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样例输入 #2样例输出 #2提示题解代码我的一些话[NOIP2017 提高组] 宝藏 题目背景 NOIP2017 D2T2 题目描…