一、前言
本文旨在记录那些常见的Linux概念和名词,但这些又没经常直接使用到,更多在底层运行,见过却又不是特别清楚的碎片知识,以温故知新。
二、知识点和概念说明
2.1、POSIX标准/协议
POSIX(Portable Operating System Interface可移植操作系统接口)是IEEE为在UNIX操作系统上运行软件而定义API的一系列互相关联的标准的总称,其正式称呼为IEEE Std 1003,POSIX.1 已经被国际标准化组织(International Standards Organization,ISO)命名为 ISO/IEC 9945-1:1990 标准。简言之,POSIX就是Unix的一种标准,主要就是IEEE当时为了提高unix生态的兼容性和应用程序的可移植性。这样,任何一个 基于POSIX 兼容的操作系统编写的程序,都可以在任何其它的 POSIX 操作系统上编译执行。之后,这些遵循Posix标准的程序就可跨平台进行POSIX系统调用,即调用一组通用的API。
相关资源:IEEE Std 1003.1-2001、
Linux之父linus在其书中提到:POSIX标准是一个可以适用于数以百计的UNIX系统调用(system call)中的任意一个的一套冗长规则, 计算机要执行任务(从读、 写、 开机和关机开始) 就需要这个标准。 Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions);其中,系统调用是操作系统本身的接口,是面向底层硬件的。通过系统调用,可以使得用户态运行的进程与硬件设备(如CPU、磁盘、打印机等)进行交互,是操作系统留给应用程序的一个接口。对于库函数(Library function),是把函数放到库里,一般是一些常用到的函数写入lib文件里,供其他人使用的一种方式,库函数调用是面向应用开发的;由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口。最常见的比如开源的标准 C 库glibc ,它提供了丰富的 API(Application Programming Interface),这些API都是遵循POSIX标准的,API的函数名,返回值,参数类型等都必须按照POSIX标准来定义。即广义的POSIX兼容也就指定这些接口函数兼容,其并不管API具体如何实现。目前的POSIX主要分为四个部分:Base Definitions、System Interfaces、Shell and Utilities和Rationale。
2.2、MPI-IO标准/协议
MPI(Message Passing Interface)是在高性能计算程序中,用于在参与计算的不同CPU、或服务器节点之间进行消息传递的一组规范或接口,通过这组接口,能帮助开发工程师们在不同的计算平台上快速编写可跨平台移植的并行计算程序,提升开发效率。基于MPI的规范和接口,业界有不同的MPI实现,如OpenMPI等。在高性能计算的世界中,除了计算,还必须有数据读写的支撑,所以除了MPI,还需要有一组跨计算平台的、可移植的、并行数据读写接口,这就是MPI-IO设计的初衷:让IO能够像消息传递(MPI)那样,通过标准的接口实现并行的数据读写访问。
传统标准的NFS Server通常只提供相当有限的并行访问能力,即单个客户端通过单一访问入口来访问数据,因此在HPC中使用并行IO策略时,难以提供足够高的性能。因此,在大型并行计算应用中,通常不使用NFS来进行数据访问。并行文件系统通常将单个文件数据分布在多个存储服务器上,而运行在多个计算节点上的并行应用程序的多个任务,经常对单个文件同时发起并发访问请求。并行文件存储系统可以通过并行的多个IO访问请求,为单个文件提供高水平的读/写带宽。
2.3、RDMA(远程直接内存访问)
RDMA(Remote Direct Memory Access)是基于消息的数据传输协议(而不是基于字节流的传输协议),数据传输都是异步操作,所有数据包的组装都在RDMA硬件上完成的,也就是说OSI模型中的下面4层(传输层,网络层,数据链路层,物理层)都在RDMA硬件上完成。它是为了解决网络传输中服务器端数据处理的延迟而产生的。RDMA通过网络把资料直接传入计算机的存储区,将数据从一个系统快速移动到远程系统存储器中,而不对操作系统造成任何影响,几乎不需要用到计算机的cou处理功能。它消除了外部存储器复制和上下文切换的开销,让内存、带宽和CPU这些可用于改进更多应用系统的性能。
另外这里我们不得不提到DMA,即直接内存访问,它是一种完全由硬件执行I/O交换的工作方式.在这种方式中, DMA 控制器(DMAC)从CPU 完全接管对总线的控制,数据交换不经过CPU ,而直接在内存和IO设备之间进行,减少大批量数据传输时CPU 的开销,也是实现zero-copy的前提。
在传统通信模式中,使用TCP/IP协议的应用程序几乎都会采用应用编程接口:UNIX BSD的套接字(socket),来实现网络进程之间的通信。无论编写客户端程序还是服务端程序,系统都需要为每个TCP连接都要创建一个socket句柄,导致每次传输通信,都要经过OS和协议栈的管理,无论是Socket同步通信还是异步通信,都会存在CPU占用过高的现象。这种传统的TCP/IP通信,发送和接收数据的过程中,都是在源端应用层数据从上向下逐层拷贝封装,目的端从下向上拷贝和解封装,需要CPU多次参与,比较慢。对此,才有了DMA和RDMA更好的数据处理实现。
RDMA让计算机可以直接存取其他计算机的内存,而不需要经过处理器的处理。RDMA可将数据从一个系统快速移动到远程系统的内存中,过程中,本地用户空间虚拟内存与RNIC(RDMA-aware Network Interface Controller)网卡直接进行数据传输不涉及到系统内核,没有额外的数据移动和复制,不会对操作系统造成任何影响。RDMA通信过程中,发送和接收,读/写操作中,都是RNIC直接和参与数据传输的已经注册过的内存区域直接进行数据传输,速度快,不需要CPU参与,RDMA网卡接替了CPU的工作,特别适用于高性能计算、大数据处理、分布式存储等场景。目前支持RDMA的网络协议主要有三种:InfiniBand(IB)、iWARP(RDMA over TCP/IP)、RoCE(RDMA over Converged Ethernet):RoCEv1和RoCEv2;RoCE v1是一种链路层协议,允许在同一个广播域下的任意两台主机直接访问。RoCE v2是一种Internet层协议,即可以路由;RoCE协议也可以使用在传统以太网网络或者非融合以太网络中;RoCE和InfiniBand,一个定义了如何在以太网上运行RDMA,而另一个则定义了如何在IB网络(主要是基于集群的应用)中运行RDMA;RoCE和iWARP,一个是基于无连接协议UDP,一个是基于面向连接的协议(如TCP)。
RDMA 的工作过程如下:
1)当一个应用执行RDMA 读或写请求时,不执行任何数据复制,在不需要任何内核内存参与的条件下, RDMA 请求从运行在用户空间中的应用中发送到本地NIC( 网卡)。
2)NIC 读取缓冲(buffer)的内容,并通过网络传送到远程NIC。
3)在网络上传输的RDMA 信息包含目标虚拟地址、内存key和数据本身,请求完成既可以完全在用户空间中处理(通过轮询用户级完成排列) ,或者在应用一直睡眠到请求完成时的情况下通过内核内存处理;RDMA 操作使应用可以从一个远程应用的内存中读数据或向这个内存写数据。
4)目标NIC 确认内存key,直接将数据写入应用缓存buffer中,用于操作的远程虚拟内存地址包含在RDMA 信息中。
使用RDMA的优势如下:
- 零拷贝(Zero-copy): 应用程序直接执行数据传输,数据能够被直接发送到缓冲区或者能够直接从缓冲区里接收,而不需要被复制到网络层。
- 内核旁路(Kernel bypass) :应用程序可以直接在用户态执行数据传输,不需要在内核态与用户态之间做上下文切换。
- 不需要CPU干预(No CPU involvement) :应用程序可以访问远程主机内存而不消耗远程主机中的任何CPU。远程主机内存能够被读取而不需要远程主机上的进程(或CPU)参与。远程主机的CPU的缓存(cache)不会被访问的内存内容所填充。
- 消息基于事务(Message based transactions) :数据被处理为离散消息而不是流,消除了应用程序将流切割为不同消息/事务的需求。
- 支持分散/聚合条目(Scatter/gather entries support) :RDMA原生态支持分散/聚合。它能取多个内存缓冲区然后作为一个流发出去或者接收一个流然后写入到多个内存缓冲区里去。
RDMA的编程接口主要包括Verbs API和RDMA CM(Connection Manager)API。Verbs API提供了一套完整的RDMA操作函数,包括内存注册、队列对(Queue Pair, QP)的创建和管理、数据发送和接收等。RDMA CM API则提供了一套用于建立和管理RDMA连接的功能。
关联资源:DAOS文件存储、分布式文件系统、juicefs、cube studio、MPI如何对Lustre/GPFS文件系统优化