Java NIO 之 零拷贝技术(上)
(一)CPU、输入输出接口和 DMA 控制器互相配合读写硬盘数据
CPU、I/O 接口和 DMA 控制器协作读写硬盘数据的基本流程如下,分读数据和写数据两种情况说明:
一、读硬盘数据(硬盘 → 内存)
- CPU 发起读请求
- CPU 向硬盘的 I/O 接口(如 SATA、NVMe 控制器)发送读命令,指定:
- 数据在硬盘上的逻辑地址(LBA, Logical Block Address)
- 目标内存地址
- 数据大小(如读取 4KB)。
- CPU 向硬盘的 I/O 接口(如 SATA、NVMe 控制器)发送读命令,指定:
- 硬盘准备数据
- 硬盘控制器根据 LBA 定位磁道/扇区(机械硬盘)或 NAND 块(SSD),将数据读取到硬盘内部的**缓存(Buffer)**中。
- DMA 初始化
- CPU 配置 DMA 控制器,设置:
- 源地址:硬盘缓存地址(通过 I/O 接口映射的寄存器地址)。
- 目标地址:内存目标地址。
- 传输长度:数据大小(如 4KB)。
- CPU 配置 DMA 控制器,设置:
- DMA 传输数据
- DMA 控制器接管系统总线,直接控制数据从硬盘缓存通过 I/O 接口传输到内存,无需 CPU 参与。
- 传输期间,CPU 可执行其他任务。
- 传输完成中断
- DMA 控制器在传输完成后,向 CPU 发送中断信号。
- CPU 收到中断后,确认数据已就绪,继续后续处理。
二、写硬盘数据(内存 → 硬盘)
- CPU 发起写请求
- CPU 向硬盘的 I/O 接口发送写命令,指定:
- 目标硬盘地址(LBA)
- 源内存地址
- 数据大小。
- CPU 向硬盘的 I/O 接口发送写命令,指定:
- DMA 初始化
- CPU 配置 DMA 控制器,设置:
- 源地址:内存源地址。
- 目标地址:硬盘缓存地址(通过 I/O 接口映射的寄存器地址)。
- 传输长度:数据大小。
- CPU 配置 DMA 控制器,设置:
- DMA 传输数据
- DMA 控制器将数据从内存通过 I/O 接口传输到硬盘缓存。
- 硬盘写入数据
- 硬盘控制器将缓存数据写入指定物理位置(磁道/扇区或 NAND 块)。
- 完成中断
- 硬盘通过 I/O 接口向 CPU 发送中断,通知写入完成。
三、关键组件作用
组件 | 核心功能 |
---|---|
CPU | 发起读写命令,配置 DMA 控制器,处理中断。 |
I/O 接口 | 协议转换(如 SATA/NVMe 到系统总线)、地址映射、状态寄存器管理。 |
DMA 控制器 | 接管总线控制权,直接完成内存与外设(硬盘)间数据传输,解放 CPU 算力。 |
硬盘控制器 | 管理硬盘物理操作(寻址、缓存读写、纠错等)。 |
四、DMA 的优势
- 减少 CPU 开销:CPU 仅需初始化传输,无需逐字节搬运数据。
- 提升系统吞吐量:数据传输与 CPU 计算可并行。
- 降低延迟:DMA 专为数据传输优化,效率高于 CPU 轮询。
五、典型场景示例
假设程序请求读取文件:
- CPU 调用驱动程序,发起读请求。
- 驱动程序配置 DMA 并触发硬盘操作。
- DMA 完成数据搬运后触发中断。
- CPU 收到中断,唤醒等待该数据的进程。
通过 DMA,CPU 仅在初始化和结束时参与,大幅提升系统效率。
(二)CPU、网卡(I/O 接口)与 DMA 控制器互相配合读写网络数据
网络数据传输的核心流程与硬盘读写类似,但需额外处理网络协议栈(如 TCP/IP)和数据包的封装/解析。以下分接收数据(网络 → 内存)和发送数据(内存 → 网络)两种情况说明:
一、接收网络数据(网络 → 内存)
- 网卡接收数据包
- 网卡通过物理链路(如以太网、WiFi)接收到数据包,解析帧头(MAC 地址、校验和等),确认目标为本机后,将数据包存入网卡内置的接收缓冲区(Rx Buffer)。
- DMA 初始化(接收)
- CPU 提前为网卡分配好内存中的接收环形缓冲区(Rx Ring Buffer),并通过驱动程序配置 DMA 控制器:
- 源地址:网卡接收缓冲区的物理地址。
- 目标地址:内存中环形缓冲区的物理地址。
- 传输长度:数据包大小(由网卡解析帧头获取)。
- CPU 提前为网卡分配好内存中的接收环形缓冲区(Rx Ring Buffer),并通过驱动程序配置 DMA 控制器:
- DMA 传输数据包到内存
- DMA 控制器自动将数据包从网卡缓冲区通过总线直接传输到内存的环形缓冲区,无需 CPU 参与逐字节拷贝。
- 传输期间,CPU 可处理其他任务。
- 网卡触发中断(或轮询)
- 中断模式:网卡通过中断通知 CPU 数据包已就绪。
- 轮询模式(如 NAPI):高吞吐场景下,CPU 主动轮询网卡状态以减少中断开销。
- CPU 处理数据包
- CPU 从环形缓冲区读取数据包,交给内核协议栈(TCP/IP)处理:
- 解析 IP 头、TCP 头,验证校验和。
- 根据端口号将数据传递给目标应用程序的 Socket 缓冲区。
- 若使用零拷贝技术(如
sendfile
或内存映射),数据可直接从内核缓冲区传递到应用,避免用户态与内核态间的拷贝。
- CPU 从环形缓冲区读取数据包,交给内核协议栈(TCP/IP)处理:
二、发送网络数据(内存 → 网络)
- CPU 准备待发送数据
- 应用程序将数据写入 Socket 发送缓冲区,内核协议栈封装 TCP/IP 头部和帧头(如目标 MAC 地址)。
- DMA 初始化(发送)
- CPU 通过驱动程序配置 DMA 控制器:
- 源地址:内存中封装好的数据包缓冲区(如 Socket 缓冲区)的物理地址。
- 目标地址:网卡发送缓冲区(Tx Buffer)的物理地址。
- 传输长度:数据包大小。
- CPU 通过驱动程序配置 DMA 控制器:
- DMA 传输数据包到网卡
- DMA 控制器将数据包从内存缓冲区直接传输到网卡发送缓冲区。
- 网卡发送数据包
- 网卡将发送缓冲区的数据按物理链路协议(如以太网)封装为帧,添加校验和,通过物理链路发送出去。
- 发送完成通知
- 网卡通过中断或状态寄存器通知 CPU 数据已发送完成,释放内存缓冲区。
三、关键组件作用
组件 | 核心功能 |
---|---|
CPU | 初始化 DMA、处理协议栈(TCP/IP 封装/解析)、响应中断、管理缓冲区。 |
网卡(I/O 接口) | 物理链路通信、数据帧解析/封装、校验和计算、DMA 地址映射、中断触发。 |
DMA 控制器 | 接管总线,直接搬运内存与网卡缓冲区间的数据,减少 CPU 拷贝开销。 |
协议栈 | 封装/解析网络协议头(如 IP、TCP)、管理连接状态、实现流量控制。 |
四、DMA 与零拷贝技术的结合
- 传统流程的瓶颈
- 未使用零拷贝时,数据需多次拷贝:
- 接收:网卡 → 内核缓冲区 → 用户态缓冲区。
- 发送:用户态缓冲区 → 内核缓冲区 → 网卡。
- 未使用零拷贝时,数据需多次拷贝:
- 零拷贝优化
sendfile
系统调用:文件数据直接从磁盘通过 DMA 传输到网卡,无需经过用户态。- 内存映射(mmap):应用程序直接访问内核缓冲区,避免用户态与内核态拷贝。
- 网卡散射-聚集(Scatter-Gather):DMA 支持从多个非连续内存区域直接聚合数据发送。
五、典型场景示例(HTTP 服务器发送文件)
- 客户端请求文件,服务端调用
sendfile
系统调用。 - DMA 将文件数据从硬盘直接传输到内存页缓存。
- 内核协议栈封装 TCP/IP 头部,DMA 将数据从页缓存传输到网卡缓冲区。
- 网卡发送数据,全程无需 CPU 参与数据拷贝。
通过 DMA 和零拷贝技术,网络数据传输的吞吐量可提升数倍,CPU 占用率显著降低。