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

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的扩容缩容机制也就分析结束了。

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

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

相关文章

Flask 入门7:使用 Flask-Moment 本地化日期和时间

如果Web应用的用户来自世界各地,那么处理日期和时间可不是一个简单的任务。服务器需要统一时间单位,这和用户所在的地理位置无关,所以一般使用协调世界时(UTC)。不过用户看到 UTC 格式的时间会感到困惑,他们…

Linux系统安装(CentOS Vmware)

学习环境安装 VMware安装 VMware下载&安装 访问官网:https://www.vmware.com 在此处可以选择语言 点击China(简体中文) 点击产品,点击Workstation Pro 下滑,点击下载试用版 下滑找到Workstation 17 Pro for Wi…

如何查看端口映射?

端口映射是一种用于实现远程访问的技术。通过将外网端口与内网设备的特定端口关联起来,可以使外部网络用户能够通过互联网访问内部网络中的设备和服务。在网络中使用端口映射可以解决远程连接需求,使用户能够远程访问设备或服务,无论是在同一…

彻底学会系列:一、机器学习之线性回归(一)

1.基本概念(basic concept) 线性回归: 有监督学习的一种算法。主要关注多个因变量和一个目标变量之间的关系。 因变量: 影响目标变量的因素: X 1 , X 2 . . . X_1, X_2... X1​,X2​... ,连续值或离散值。 目标变量: …

DAY7 作业

1.简易QQ登录页面 实际效果 qss界面代码 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);this->setWindowTitle("QQ"); /*设置窗口标题*/this->…

python官网下载慢怎么办?这里是一些解决方法

为什么Python官网下载速度慢? Python官网是开源软件的官方网站,提供了Python编程语言的最新版本和相关资源供开发者下载。然而,由于全球用户访问量较大,有时候会导致Python官网的下载速度变慢或不稳定。这对于急需获取Python的开…

idea设置terminal为git

要在IntelliJ IDEA中设置终端为Git Bash,请按照以下步骤操作: 打开 Settings(设置)。点击 Tools(工具)选项卡。进入 Terminal(终端)界面。在 Shell Path 下选择 Browse(…

如何在 Microsoft Azure 上部署和管理 Elastic Stack

作者:来自 Elastic Osman Ishaq Elastic 用户可以从 Azure 门户中查找、部署和管理 Elasticsearch。 此集成提供了简化的入门体验,所有这些都使用你已知的 Azure 门户和工具,因此你可以轻松部署 Elastic,而无需注册外部服务或配置…

【git】本地项目推送到github、合并分支的使用

1. github上创建仓库信息 点击个人头像,选择【你的仓库】 点击【新增】 填写仓库信息 2. 本地项目执行的操作 1.生成本地的git管理 (会生成一个.git的文件夹) git init 2.正常提交到暂存区,并填写提交消息 git add . git commit -m "init…

c语言--指针数组(详解)

目录 一、什么是指针数组?二、指针数组模拟二维数组 一、什么是指针数组? 指针数组是指针还是数组? 我们类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。 那指针数组呢?是存放…

[每日一题] 02.07 - 小鱼比可爱

小鱼比可爱 n int(input()) lis list(map(int,input().split())) res [0] for i in range(1,n):count 0for j in range(i):if lis[i] > lis[j]:count 1res.append(count)a .join(str(i) for i in res) print(a[:-1])

【大模型上下文长度扩展】MedGPT:解决遗忘 + 永久记忆 + 无限上下文

MedGPT:解决遗忘 永久记忆 无限上下文 问题:如何提升语言模型在长对话中的记忆和处理能力?子问题1:有限上下文窗口的限制子问题2:复杂文档处理的挑战子问题3:长期记忆的维护子问题4:即时信息检…

pytorch训练指标记录之tensoboard,wandb

详解Tensorboard及使用教程_tensorboard怎么用-CSDN博客文章浏览阅读5.1w次,点赞109次,收藏456次。目录一、什么是Tensorboard二、配置Tensorboard环境要求安装三、Tensorboard的使用使用各种add方法记录数据单条曲线(scalar)多条曲线(scalars)直方图(hi…

借助宁盾身份目录实现信创、Windows混合终端统一身份认证及网络准入控制

背景: 近期有基金、保险行业的IT负责人反馈,公司要求IT建设必须紧跟政策,在2024年内必须要上国产信创操作系统终端,个别应用如OA系统、虚拟化桌面、邮箱等都不能再继续用国外的产品了,要完成国产化替代指标。跟着国产…

【动态规划】【前缀和】【C++算法】LCP 57. 打地鼠

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LCP 57. 打地鼠 勇者面前有一个大小为3*3 的打地鼠游戏机,地鼠将随机出现在各个位置,moles[i] [t,x,y] 表…

踩坑实录(Third Day)

临近年关,同事们该回家的也都回家了,所以我对工作的欲望不是很强烈,所以就主要是自己学习了一下,在 B 站看看视频,自己敲代码,所以今天没遇到什么坑,但是可以分享一下之前踩到的两个坑。 此为第…

Flutter开发模仿百度云盘创建文件夹功能Draggable和DragTarget的混合使用

使用LongPressDraggable和DragTarget写了个类似于百度云盘管理文件和文件夹的功能(为了避免和列表的滑动手势冲突,所以采用LongPressDraggable而不是Draggable): 1、拖拽文件到文件夹中 2、拖拽两个文件可以合并成一个新的文件夹…

flask+pyinstaller实现mock接口,并打包到exe运行使用postman验证

flask代码 from flask import Flask, request, jsonifyapp Flask(__name__)app.route("/login", methods[POST]) def login():username request.json.get("username").strip() # 用户名password request.json.get("password").strip() # 密…

Git介绍和常用命令说明

目录 一、Git概述 1.1 Git是什么 1.2 Git有什么用 1.3 Git仓库介绍 二、Git下载与安装 三、Git代码托管服务(远程仓库) 四、Git常用命令 4.1 设置用户信息 4.2 获取Git仓库 4.2.1 本地初始化Git仓库 4.2.2 从远程仓库克隆 4.3 本地仓库操作 …

【Spring源码解读!底层原理进阶】【下】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨

🎉🎉欢迎光临🎉🎉 🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀 🌟特别推荐给大家我的最新专栏《Spring 狂野之旅:底层原理高级进阶》 &#x1f680…