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

互联网三高-高性能之IO网络技术底层机制

1 DMA技术

        1.1 概念

                直接内存访问

                允许某些硬件系统能够独立于CPU直接读写操作系统内存,不需要CPU介入

                DMAC(DMA控制器)控制数据传输操作,这时CPU可以去做其他操作

        1.2 应用程序从磁盘读取数据

        1.3 DMA工作

                ① 从磁盘缓冲区到内核缓冲区的拷贝工作 (读)

                ② 从网卡设备到内核的 Socket Buffer 的拷贝工作(读)

                ③ 从内核缓冲区到磁盘缓冲区的拷贝工作(写)

                ④ 从Socket Buffer 到内核的 网卡设备 的拷贝工作(写)

        1.4 DMA性能损害

                4次内核态和用户态之间的上下文切换

                4次缓冲区拷贝

2 零拷贝

        2.1 零拷贝作用

                减少不必要的内核缓冲区和用户缓冲区的拷贝工作

                减少内核态和用户态的上下文切换

        2.2 零拷贝技术实现

                (1)方式一:mmap + write(2个函数)

                        ① 原理

                                操作系统使用虚拟地址,多个虚拟地址可以指向用一个物理地址

                                把内核空间和用户空间的虚拟地址映射到同一个物理地址,就不需要来回复制数据了

                                mmap系统函数:把内核缓冲区数据映射到用户空间

                        ② 损耗

                                4次内核态和用户态之间的上下文切换

                                3次拷贝(2次DMA拷贝,1次CPU拷贝)

                        ③ 哪些框架使用了这个

                                RocketMQ:主要是mmap,也有小部分使用sendfile

                                        消息存盘和网络发送使用mmap,单个commitLog文件大小默认为1G

                (2)方式二:sendfile(函数)

                        ① 原理

                                sendfile()函数,替代了read()和write()两个系统调用    

                        ② 损耗

                                2次用户态和内核态之间的上下文切换

                                3次拷贝(2次DMA拷贝,1次CPU拷贝) 

                      ③ 改进

                                Linux2.4+版本改进了sendfile,利用DMA Gather(带有收集功能的DMA),变成了真正的零拷贝(没有了CPU拷贝)

                         ④ 改进版损耗

                                2次用户态和内核态之间的上下文切换

                                2次拷贝(2次DMA拷贝)

                        ⑤ 哪些框架使用

                                Nginx

                                Kafka:主要是snedfile,小部分使用mmap

                                        在客户端和Broker进行数据传输时,Broker使用sendfile函数调用

3 Java使用零拷贝(依赖于底层的系统实现)

        3.1 FileChannel:文件通道

                是Java NIO中用于文件读/写、内存映射、数据强制持久化及高效传输的核心通道类,其底层通过操作系统原生接口实现文件操作,支持线程安全并发访问,常被用于高效的网络/文件的数据传输。

                (1)创建方式

                        只读:FileInputStream.getChannel()

                        可写:FileOutputStream.getChannel()

                        读写:RandomAccessFile.getChannel()

                (2)mmap的实现

                        map()方法:MappedByteBuffer map(MapMode mode,long position, long size)

                                把文件映射成内存映射文件

                                一次map大小限制为2G,过大map会增加虚拟内存回收和重新分配的压力,直接报错

                (3)sendfile的实现

                        ① transferTo():long transferTo(long position, long count, WritableByteChannel target)

                                将字节从此通道的文件传输到给定的可写入字节通道

                                返回值为真实拷贝的size,最大拷贝为2G,超过2G部分将丢弃

                        ② transferFrom():long transferFrom(ReadableByteChannel src,long position, long count)

                                将字节从给定的可读取字节通道传输到此通道的文件中

                        注意:只有FileChannel才支持transfer这种高效复制方式,SocketChannel等都不支持transfer模式。

                        FileChannel --> FileChannel

                        FileChannel --> SocketChannel

        3.2 Java文件拷贝不同方式

                (1)普通的Java IO流

/*** 普通的Java IO流 完成文件复制* @param inputFilePath* @param outputFilePath*/
private static void inputStreamCopyFile(String inputFilePath, String outputFilePath) {final long start = System.currentTimeMillis();try(FileInputStream fis = new FileInputStream(inputFilePath);final FileOutputStream fos = new FileOutputStream(outputFilePath);) {byte[] b = new byte[64];int len;while ((len = fis.read(b)) != -1) {fos.write(b);}} catch (Exception e) {e.printStackTrace();}final long end = System.currentTimeMillis();log.info("【inputStreamCopyFile】,总耗时:{}", (end - start));
}

        

                (2)普通的Java带Buffer的IO流

/*** 普通的Java带Buffer的IO流 完成文件复制* @param inputFilePath* @param outputFilePath*/
private static void bufferedInputStreamCopyFile(String inputFilePath, String outputFilePath) {final long start = System.currentTimeMillis();try(final BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputFilePath));final BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputFilePath));) {byte[] b = new byte[64];int len;while ((len = bis.read(b)) != -1) {bos.write(b);}} catch (Exception e) {e.printStackTrace();}final long end = System.currentTimeMillis();log.info("【bufferedInputStreamCopyFile】,总耗时:{}", (end - start));
}

        

                (3)零拷贝实现之mmap的IO流

/*** 零拷贝实现之mmap的IO流 完成文件复制* @param inputFilePath* @param outputFilePath*/
private static void mmapCopyFile(String inputFilePath, String outputFilePath) {final long start = System.currentTimeMillis();try(final FileChannel inputChannel = new FileInputStream(inputFilePath).getChannel();final FileChannel outputChannel = new RandomAccessFile(outputFilePath,"rw").getChannel();) {long size = inputChannel.size();log.info("【mmapCopyFile】 fileSize: {}", size);final MappedByteBuffer mapIn = inputChannel.map(FileChannel.MapMode.READ_ONLY, 0, size);final MappedByteBuffer mapOut = outputChannel.map(FileChannel.MapMode.READ_WRITE, 0, size);for(int i=0; i<size; i++) {final byte b = mapIn.get(i);mapOut.put(b);}} catch (Exception e) {e.printStackTrace();}final long end = System.currentTimeMillis();log.info("【mmapCopyFile】,总耗时:{}", (end - start));
}

        

                (4)零拷贝实现之sendfile的IO流

/*** 零拷贝实现之sendfile的IO流 完成文件复制* @param inputFilePath* @param outputFilePath*/
private static void sendfileCopyFile(String inputFilePath, String outputFilePath) {final long start = System.currentTimeMillis();try(final FileChannel inputChannel = new FileInputStream(inputFilePath).getChannel();final FileChannel outputChannel = new FileOutputStream(outputFilePath).getChannel();) {// 方式1:针对小于2G的,最大拷贝为2G,超过2G部分将丢弃// inputChannel.transferTo(0,inputChannel.size(), outputChannel);// 方式1:针对大于2G的final long size = inputChannel.size();for(long left = size; left > 0;) {final long transferSize = inputChannel.transferTo((size - left), left, outputChannel);// 剩下还有多少left = left - transferSize;log.info("文件总大小:{},拷贝大小:{},剩下大小:{}", size, transferSize, left);}} catch (Exception e) {e.printStackTrace();}final long end = System.currentTimeMillis();log.info("【sendfileCopyFile】,总耗时:{}", (end - start));
}

        

4 TCP底层设计交互原理

        4.1 三次握手

               三次握手流程

                        ① 一次握手:客户端发送一个SYN数据包到服务端,用来请求建立连接,状态变为SYN_SEND(同步发送状态)

                                报文中,SYN=1,同时随机生成初始序列seq=x

                        ② 二次握手:服务端接收到客户端的SYN数据包,并回复一个SYN+ACK数据包,用来确认连接,状态变为SYN_RECEIVED(同步接收状态)

                                确认报文中,ACK=1,SYN=1,确认序号是ack=x+1,同时随机初始化一个序列号 seq=y

                        ③ 三次握手:客户端收到服务器的SYN+ACK数据包,并回复一个ACK数据包,用来确认连接建立完成,状态变为ESTABLISHED(建⽴连接)

                                确认报文 ACK=1,ack=y+1,seq=x+1

                                第三次握手可以携带数据了

        4.2 四次挥手

                四次挥手流程

                        ① 一次挥手:客户端发送FIN报文段,用于关闭客户端到服务端的数据传输,表示客户端的数据发送完毕,客户端进入FIN_WAIT_1状态

                        ② 二次挥手:服务端收到客户端的FIN报文段后,发送ACK报文段,确认收到了客户端的FIN报文段,服务端进入CLOSE_WAIT状态,客户端接收到这个确认包后进入FIN_WAIT_2状态

                        ③ 三次挥手:服务端发送FIN报文段,用于关闭服务端到客户端的数据传输,表示服务端的数据发送完毕,服务端进入LAST_ACK状态,等待客户端的最后一个ACK

                        ④ 四次挥手:客户端收到服务端的FIN报文段后,发送ACK报文段,确认收到了服务端的FIN报文段;客户端接收后进入TIME_WAIT状态,在此阶段下等待2MSL时间(2个最大段生命周期),如果这个时间间隔内没有收到服务端的请求,进入CLOSED状态;服务端接收到ACK确认包后,也进入CLOSED状态        

http://www.xdnf.cn/news/1238.html

相关文章:

  • 《TCP/IP详解 卷1:协议》之第四、五章:ARP RARP
  • CLIP | 训练过程中图像特征和文本特征的在嵌入空间中的对齐(两个投影矩阵的学习)
  • 武装Burp Suite工具:RouteVulScan插件_被动扫描发现漏洞.
  • python高级特性01
  • 代码随想录算法训练营Day34
  • (16)VTK C++开发示例 --- 转换文件格式
  • ProxySQL 性能调优工具推荐
  • day48—双指针-通过删除字母匹配到字典最长单词(LeetCode-524)
  • 【随机过程】柯尔莫哥洛夫微分方程总结
  • 算力网络的早期有关论文——自用笔记
  • 在Pytorch中使用Tensorboard可视化训练过程
  • 基于DeepSeek的网络爬虫技术创新与实践应用
  • 若依如何切换 tab 不刷新
  • Google 开发者政策中心 - 3 月版
  • 【Spring】AutoConfigureOrder与Order注解的区别与使用方式
  • Gboard安卓版手势输入与多语言支持全面评测【输入顺滑】
  • Java数组
  • C++抽象基类定义与使用
  • linux kallsys
  • 探索Cangjie Magic:仓颉编程语言原生的LLM Agent开发新范式
  • mcp 客户端sse远程调用服务端与本地大模型集成实例
  • Python简介与入门
  • 多路转接select服务器
  • 数据结构:链表
  • 近几年字节测开部分面试题整理
  • 明远智睿2351开发板四核1.4G Linux处理器:驱动创新的引擎
  • Protues8.11安装只需5步骤即可。
  • 如何创建Vue3工程
  • 状态管理最佳实践:Riverpod响应式编程
  • 理解 C++ 中的隐式构造及其危害