文章目录
1. What is SGL?
sgl(Scatter-Gather List)内存传输技术,是一种高效管理非连续内存数据传输的方法。
核心思想:通过一个链表或数组描述多个分散的内存块,使得硬件可以一次性完成对这些非连续内存区域的读写操作,无需CPU介入数据拷贝。
2. sgl内存传输的原理
2.1 核心思想
主要聚焦在分散、聚集、零拷贝上:
- 分散-聚集 Scatter-Gather
- 分散:将数据从一块连续缓存区拆分为多个块,写入多个非连续的内存区域;
- 聚集:从多个非连续的内存区域读取数据,合并为一块连续的流。
- 零拷贝 zero-copy
- 零拷贝是避免数据在内存中的多次拷贝(如用户态和内核态之间、内核与设备之间),直接通过内存地址描述符完成传输。
2.2 sgl数据结构
以sgl链表为例,每个条目(Entery)包含的内容:
- 内存块的物理地址
- 内存块的长度
- 指向下一个节点的指针
整体结构:通常以链表或数组的形式组织多个条目,比如:
sgl entry1 : 地址0x1000,长度512B,指向entry2的指针
sgl entry2 : 地址0x2000,长度1024B,指向entry3的指针
sgl entry3 : 地址0x3000,长度256B,NULL
2.3 摘链和挂链
摘链是从SGL链表中移除一个或多个节点的操作,通常用于以下场景:
- 传输完成:当某个节点对应的内存数据传输完成后,释放该节点资源;
- 错误处理:传输过程中发生错误,需要中断并清理部分已经处理的节点;
- 动态调整:根据传输进度动态缩减SGL链表的规模
挂链是将新的节点添加到SGL链表中的操作,通常用于以下场景:
- 动态扩展传输:传输过程中需要追加新的内存块;
- 预构建SGL:初始化时逐步添加多个内存块节点;
- 错误恢复:重传时需要重新挂载节点
挂链和摘链也伴随着加减计数:
- 加计数:新增SGL条目、或扩展传输范围时,进行加计数;
- 减计数:完成条目传输、释放资源时,进行减计数。用于标记已经传输的数据块,释放内存或复用缓冲区,避免资源泄露
3. 零拷贝技术
零拷贝zero-copy技术,是一种优化数据传输效率的方法,旨在消除或减少数据在内存中的冗余拷贝操作,从而降低CPU开销、节省内存带宽并减少延迟。该技术广泛应用于网络通信、文件传输、存储系统和高性能计算等领域。
3.1 问题背景
传统数据传输存在的问题:
例如从文件读取数据并通过网络发送:
- 文件数据从磁盘读取到内核缓冲区(page cache);
- 数据从内核缓冲区拷贝到用户态缓存区(应用层内存);
- 数据从用户态缓冲区再拷贝到内核的网络缓冲区(socket buffer);
- 最后通过网卡发送数据。
该方式存在的问题:
- 多次数据拷贝:数据在内核态和用户态之间来回复制;
- cpu开销高:cpu需要参与数据搬运,占用大量计算资源;
- 内存带宽浪费:冗余拷贝消耗内存带宽,影响系统整体性能。
3.2 零拷贝的核心思想及实现方式
零拷贝技术,通过绕过用户态,直接在内核态或硬件设备间传输数据,减少甚至消除数据拷贝次数。
零拷贝的实现方式,大概有:
- 内存映射 Memory Mapping,mmap
- 原理:将文件直接映射到用户态进程的虚拟内存空间,进程通过指针直接读写文件,无需通过
read()/write()
系统调用 - 实现流程:调用
mmap()
将文件映射到用户空间;进程直接操作映射的内存区域,修改会自动同步到文件。
- 原理:将文件直接映射到用户态进程的虚拟内存空间,进程通过指针直接读写文件,无需通过
- sendfile()系统调用
- 原理:直接在两个文件描述符(如文件到socket)之间传输数据,全程在内核态完成
- 实现流程(以Linux为例):调用
sendfile()
;数据从文件的page cache直接拷贝到socket缓冲区;网卡通过DMA从socket缓冲区读取数据发送
- 硬件辅助的零拷贝
- 原理:结合DMA控制器和SGL,设备直接访问多个非连续内存块,无需CPU拷贝
- 实现流程:构建SGL描述数据的内存地址和长度;网卡或磁盘控制器通过DMA按SGL直接读写内存
4. sgl在存储行业的应用
以分布式存储与对象存储为例,对象存储系统需要将大对象拆分为多个分片存储在不同节点:将对象分片的存储节点地址和偏移量写入sgl,客户端或服务端通过sgl并发读写多个分片。
再例如,文件数据在内存中可能分散在多个page cache页(例如大文件被拆分为多个4KB页):文件系统将文件的page cache页地址构建为sgl,存储设备通过sgl直接读取这些页,无需合并到连续内存。
sgl内存传输技术通过消除数据拷贝、直接操作非连续内存块,成为存储行业高性能I/O的核心技术