在正式开始今天的分享之前,我先简单的介绍一下百度沧海·存储。
百度沧海·存储是百度智能云存储的整体品牌,源自百度内部多年来在存储技术方面的沉淀。这些技术支撑了百度搜索、百度网盘、自动驾驶等一系列大规模业务场景。
百度沧海存储在这么多年的探索和发展过程中,形成了一套存算协同、软硬融合、云边一体的整体技术平台。平台推出对象存储 BOS,块存储 CDS,文件存储 CFS 和并行文件存储 PFS 等一系列存储产品,能够满足不同场景的需求。
同时,我们也有完备的私有化和混合云的解决方案,赋能不同行业、不同体量的客户的实际需求。百度沧海·存储也是百度智能云在行业解决方案中的重要组成部分,这些解决方案里包括一些大家熟知的、百度很擅长的领域,如自动驾驶、AI大模型的训练、搜索、网盘等。
接下来我们就进入这次分享的主题,将围绕四个部分展开。
第一部分介绍一下高性能计算场景下面临哪些存储问题,第二部分简要介绍一下百度内部的高性能存储实践经验,第三部分介绍百度沧海是如何解答这些存储问题的,最后是一个客户案例。
1. 高性能场景下的存储问题
1.1. 什么是高性能计算
高性能计算是 High Performance Computing 的缩写,简称 HPC。这并不是这些年来才出现的一个词,已经有很长时间的历史了,假如我们去查阅维基百科的话,会发现在维基百科实际上把 HPC 当做超级计算机的一个同义词汇,而超级计算机是这样定义的:就是那些性能上比同时代的个人计算机快到至少一到两级的计算机,可以叫做超级计算机。
提到超级计算机这个词的时候,大家一定不要把它想象成一台巨大的机器,实际上一个超级计算机通常是一整个集群的机器,分布在一个数据中心内部。国内目前最强大的超级计算机是太湖之光,在高性能计算 TOP 500 榜单上处于第四的位置。它最大的一个特点就是所使用的 CPU 都是国产的。HPC 领域近年来呈现出一些新的发展趋势:
趋势一:高性能计算场景越来越丰富了。HPC 在原来的使用上主要是局限在一些科学计算、工业仿真这样的一些传统场景,现在越来越多的行业发现,高性能计算能够解决他们的实际问题,开始采纳高性能计算的方法和方案。
趋势二:高性能计算上云越来越流行。随着云计算的发展,云厂商提供的网络、存储、计算的硬件设施性能越来越好,一些原来因硬件性能问题没有办法上云的高性能计算具备了上云的条件,云原生或者混合云的计算模式变得越来越流行。云上进行高性能计算的最大优势就是弹性。传统超级计算机在建设的时候需要提前规划资源需求,建设庞大的数据中心,前期利用率不高资源浪费大,后期扩建成本高昂,普通客户也很难享受到高性能计算的红利。但云的弹性可以让用户很容易运行高性能计算程序,有计算需求时随时按需创建资源,计算完销毁资源。在这种模式下,用户实际上只需要为当时正在使用的资源付费,因此可以节省很多成本。
趋势三:跨界合作变得越来越普遍。近些年来业界观察到,大数据和 AI 实际上也是两种以计算为主的场景。和 HPC 相比,在方法上可以互相借鉴、互通有无。这些种类的计算之间的边界正变得越来越模糊。一方面 AI 和大数据领域在积极地吸纳传统 HPC 里面的一些方法,另外一方面传统的 HPC 也开始意识到,GPU 这样的专用硬件在特定运算方面会比 CPU 快很多,所以从业人员也在有意识地引入 GPU 的硬件和一些新的计算方法。
在这些发展趋势的推动下,如今我们谈论高性能计算的时候,通常是指三类计算:
第一类是传统意义上的超级计算机,通常就叫 HPC。气象预报、石油勘探、碰撞仿真是典型的 HPC 应用。
第二类是人工智能领域的计算,叫 AI HPC,或者直接简称 AI。这一类计算有一个特点是会大量的使用 GPU 算力,主要的场景包括大规模的深度学习训练等。
第三类是跟大数据结合的一类高性能计算,叫高性能数据分析HPDA。最近一些年,大家可能会关注了一个新闻,很多国家的科学家一起成立了一个人类基因组计划,对人类的基因组进行测序。基因测序就是一个很典型的 HPDA 场景。
国外的一些市场调研的机构对这三类场景的市场份额进行了调研。从调研的数据,我们可以发现,传统 HPC 在高性能计算领域仍然占据了主导地位,但是 AI HPC 和 HPDA 占据的市场份额其实在逐年扩大。
以上就是三种典型的高性能计算,接下来我来跟大家分享一下,在这些场景里面到底面临哪些存储问题。
1.2. 传统 HPC 中的存储问题
传统HPC有很多科学计算问题,例如方程式的求解,这里很重要的一个基础问题就是矩阵运算。当一个矩阵非常大的时候,需要将矩阵拆解成很多子矩阵,由多个节点来协作完成计算。下面举一个简单的例子来描述一下这个过程。
四个进程 P1,P2,P3,P4,一起计算一个很大的矩阵,每一个进程分到了矩阵的一个子矩阵,负责子矩阵的运算。
这一整个矩阵在存储系统里面是用一个大文件来表示的。这实际上是一个很自然的表示,如果我们对 C 语言或者其它的编程语言有一定了解,就会知道,编程语言在内存中去模拟多维数组或矩阵的时候,会使用一个连续的内存空间,通过下标计算出在连续内存空间中的偏移(offset),从而得到元素的实际存储位置。这是一个很直观的表达方法,在 HPC 计算里面,也采用类似的表达方式,只是数据不是在内存里,而是在存储系统的文件上。
这样的一种表示方式虽然逻辑上简单,但带来了两个问题需要解决。
第一个问题是 I/O 效率问题。每一个进程负责的数据,实际上会散落到矩阵文件不连续的位置上面,这些位置可能在不同的节点或者不同的存储设备上。这就会导致每个进程分别访问矩阵文件去存数据或者取数据的时候,产生大量随机的小 I/O。随机 I/O 对存储系统是不够友好的,如果存储系统的设备是机械硬盘就更糟糕。
第二个问题是进程协同问题。整个矩阵只有都计算完了之后才是有意义的,因此这些参与计算的进程之间还需要有一个协同,等每一部分计算完了之后要告诉大家,我的运算结束了。当所有进程的计算都结束了,数据写到存储系统里,才能认为是整个过程结束了。这就需要一个进程协同机制来保证。
为了解决这个两个问题,传统 HPC 里面提出了一个两阶段 I/O 的优化方法,这个方法的核心的思想就是汇聚。
假如大家对存储系统有一定了解的话,会有这样的一个认识,就是那些大的、顺序的 I/O,对于整个存储系统来说,是表现最好的。在 HPC 里面,两阶段 I/O 要做的就是想办法把那些小 I/O 汇聚成大 I/O。具体是这样做的,从那些参与计算的进程里面去挑选出来一些 I/O 进程,由这些进程去负责存储设备数据的读写,不同的进程负责的部分不重叠,最好和存储设备能够一一对应上。这样其它进程如果想要访问数据的时候,会路由到具体负责的进程上去处理,由这个进程统一处理。在整个计算过程中,这些负责 I/O 的进程实际上是可以先把数据缓存在内存里面的,然后等到整个计算完了之后,再把数据保存回文件,刷回到存储设备中。这个中间里面产生的一些进程协作的问题,也是由这个方法来完成的。通过在 MPI 框架中实现这个方法,HPC 把整个过程的细节对上层的计算隐藏掉了,整体上使用起来非常的简单和高效。
在这个过程中,我们就可以归纳出传统的 HPC 对存储的一些要求。首先在接口上,需要一个文件接口(POSIX),文件接口能够很好地支持多进程的并发随机读写。在这个文件接口之上,再去支持好上面说的两阶段 I/O,这就是 HPC 最常用的 MPI 框架 I/O 部分(MPI-I/O)做的事情。因此,HPC 的接口要求是 POSIX 文件接口和 MPI-I/O 框架支持。
在一些很大规模的训练里面,对整个吞吐的要求也是非常高的,通常会达到数十 GB/s 甚至数百 GB/s。
最后就是在延时方面,因为这些计算包含的矩阵运算会分为很多轮,一轮轮运算直至收敛,所以数据保存和读矩阵的耗时是非常关键的,反馈到存储系统就是 HPC 对延时有很苛刻的要求。
1.3. AI HPC 中的存储问题
AI HPC 实际上跟传统 HPC 相似的地方在于一个典型的计算也是分为很多轮。在每一轮计算中,不同的计算节点会去从存储系统把数据先预读上来,进行一些预处理,预处理完了之后由 GPU 来进行运算。在这个读的过程中,每个计算的节点其实只是负责了整个大的训练样本集合中的一小部分。这个读取工作实际上是通过训练框架内置的 Data Loader 机制来完成。整个过程中存在大量的读 I/O,如果样本都很小,就是大量的小 I/O。
在大规模的训练中,训练任务会周期性地做一些状态的保存,叫做 checkpoint,这里状态的保存主要起到故障恢复的作用。如果一个训练的耗费的时间非常长,在训练中间遇到一些机器故障重新做计算的代价就会很高。假如说有一些已经保存好的状态可以加载上来,接着这个状态把丢失掉的数据重新算一遍,这样会比完全重新计算要快很多。因此,在训练过程中产生的 checkpoint,可以减少需要故障恢复的数据量。这个过程以写 I/O 为主,在训练中的占比较小。
尽管越来越多的框架开始支持对象存储等接口类型,但这些接口形式使用门槛较高,被广泛接受还需要时间。文件接口依然是这个领域最主流的接口形式,被数据科学家、平台工程师、用户熟悉。
通常在生产环境下面,我们的 GPU 资源是非常宝贵的,绝大部分的企业会想去提高GPU 的利用率,这个时候就需要有一个训练调度的平台,来帮助我们做资源的调度方面的一些工作,优化资源使用。在优化资源的同时,这些调度平台可以起到的另外一个作用是屏蔽掉存储系统的细节,简化整个 AI 训练使用存储的复杂度。当下业界已经公认的一个发展趋势就是使用 K8s 这样的调度系统来完成 AI 训练的调度,这也就要求存储系统能够接入 K8s CSI 体系。
在 GPU 训练中,读写存储系统工作通常是由操作系统内核来完成的。具体落实的时候是内核使用 CPU 先将数据拷贝到内存里,GPU 使用数据的时候再拷贝到显存中。硬件厂商如 NVIDIA 在探索的一个优化是让 GPU 直接去读取存储系统,从而减少 CPU 和 GPU 间的这一次拷贝开销,同时降低 CPU 使用率。这个技术叫 GPU Direct Storage(GDS),如果能够支持它的话,能够让 GPU 训练在数据读写速度方面有更好的表现。不过目前这个技术在业界使用得并不广泛,在未来它的发展前景怎么样,我们还有待观察。
归纳下来,AI HPC 对存储接口的需求是 POSIX、K8s CSI,可选支持 GDS。
接口层面之外,不同的 AI 训练在负载方面有不同的特点,但是很多的 AI 训练会有海量小文件的需求。例如,在一些图片相关的训练中,每一个图片都很小,但是整个图片的样本集,假如展开来看的话会有非常多的小文件,一个样本集文件数多达几百万上千万都是有可能的。在整个的训练过程中,实际上对于那些样本集里的图片数据是不会做任何修改的,所以它对存储系统的 I/O 需求实际上是以读为主的。跟 HPC一样,为了读取的高效率,需要满足高吞吐和低延时的要求。此外,部分训练涉及到海量小文件的问题,海量小文件的特点就是元数据请求占比较高,存储系统的元数据性能至关重要。
1.4. HPDA 中的存储问题
因为 HPDA 就是跟大数据结合的一类高性能计算,所以说它的整个特点就跟大数据一样。例如,我们去观察一个典型的 MapReduce 的任务,会发现在 Map 阶段,Map Task 会去存储系统里面去把数据读取出来,然后进行运算,整个一轮运算的结束的 Reduce Task 会把产生的数据再存回存储系统里面。在这一类的场景里面,最早大家都是去使用 Hadoop 自带的 HDFS 来作为存储系统,随着业界开始流行一些存算分离的架构,大家发现,这一类计算使用对象存储来运行,成本更低,扩展性更好。Hadoop 的客户端在设计的时候就考虑了第三方存储系统的兼容需求,存储系统只要兼容 Hadoop 的存储接口,也就是 HCFS,就可以很方便的被大数据体系所使用。
HPDA 整个负载特点是以大文件为主,对延时不是特别的敏感,但是对吞吐要求非常的高。
1.5. 高性能计算场景存储需求的总结
现在可以简单地对这三类高性能计算的场景做一个总结。
首先在性能方面,我们会发现,这些计算对存储的需求,绝大部分情况下是发生在一批计算前面数据加载的阶段,和最后的数据保存阶段,这两个阶段如果存储性能跟不上的话,会导致 GPU、CPU 在那里等待,无事可做,空转浪费算力。GPU、CPU 在成本上来说是远高于存储成本的,存储一定要减少它们的等待时间。这些场景共性的要求是高吞吐,对一些 HPC 或者 AI HPC 的场景,还有额外的低延时要求。
第二点是文件大小的方面。这里面 AI HPC 场景比较特殊,它有海量小文件的需求,海量小文件实际上对整个存储系统的扩展性以及元数据性能方面的挑战是比较大的。
第三点是接口方面。到目前为止,POSIX 文件接口还是最主流的。HCFS 是 POSIX的一个子集,满足了 POSIX 要求后很容易开发 HCFS SDK。HPC 比较特殊,除了完整的 POSIX 兼容性之外,还需要去适配 MPI-I/O 框架。
第四点是对于所有存储系统的一个通用需求。对于非常重要的数据,我们有数据持久化要求,确保数据不会丢失。对于一些特殊的计算场景,这个要求可以放松,在一些多轮计算中,部分结果是中间生成的临时结果,这些临时结果可以通过计算重新生成。对于这些临时的结果,可以选择使用一些临时存储空间来存放,以换取更高的运算速度,更低的成本。这种临时存储空间需求在 HPC 和 AI HPC 中比较普遍,存储系统可以使用单副本来满足。
最后一点,也是大家去使用存储系统的一个通用需求,就是希望在满足性能需求的前提下,存储这方面花的成本越低越好,当下企业有很多的原始数据和历史数据需要保存,这一点显得更为重要。
2. 百度内部的高性能存储实践
百度内部高性能计算场景面临的情况是非常复杂的。百度的高性能计算中,传统 HPC计算的比重是相对比较少的,主要是以 AI HPC 和 HPDA 为主。这些计算包含很多的业务,包括自动驾驶、语音识别、广告推荐之类,这些不同的业务有各自的特点,高吞吐、低延时、大文件、小文件的需求皆有。在计算硬件方面,也有很多不同的选择,例如一些业务可能主要用 GPU 来做训练,另外有些业务主要用 CPU,百度内部也有自研的一体机和类似于昆仑芯这样的 AI 专用芯片。这就导致从计算侧来看,百度内部存储无论是业务的种类、业务的规模,还是业务的复杂度,面临的挑战都是比较大的。
百度内部实践经验中,最核心的一点就是有一个统一的存储底座来做数据的流转中心。大家可以想一下,整个高性能计算的过程实际上是分为很多个环节的。比如说自动驾驶,要从很多的全国的道路采集路况信息,数据收集完了需要做一些预处理,例如给行人、机动车、交通标示牌做标注之类的。做完标注之后,才是真正的训练过程,训练完了之后会产生一些需要部署到生产系统上的模型,所以还要去做模型的管理、模型的部署。假如这些数据分散在不同的存储系统上的话,对使用效率和使用方便程度上来讲,是一个比较大的挑战。所以百度内部使用了一个统一的存储底座来简化数据的管理和流转。
存储底座的核心能力是高可靠、低成本、高吞吐。首先看可靠性,使用了统一的存储底座之后,存储底座是数据最可靠、甚至是唯一的数据来源,需要保证数据万无一失。在这个基础上,底座存储的数据量非常之大,需要在成本方面需要做到比较优。最后,它作为一个统一的数据流转中心,需要有足够的吞吐能力,能够支撑很多的流程在上面并发运行。
在这个统一存储底座的基础之上,会去支持一些高性能计算常用的接口需求,包括POSIX 文件接口以及 HCFS 大数据接口。一些对性能有更高要求的一些业务,愿意去做一些定制开发的话,它可以直接用存储底座提供的 SDK。
到了关键的训练环节,也就是计算环节,百度内部采用了不同的运行时解决方案来满足业务多样化的诉求,主要分为两类:
第一类解决方案解决 AI 训练中存在的海量小文件问题。对于存储底座来说,它首先要保证的是高吞吐和低成本,会采用一些相对比较廉价的存储介质,虽然单个设备的能力较差,但规模上来之后就有了规模效应,可以提供很大的吞吐。但这也导致它在处理小文件的时候,在元数据方面以及 I/O 方面的性能是不太理想的,这个时候就需要有一些速度更快的解决方案作为弥补。在百度内部,根据数据集的大小,业务可以有两种选择,包括本地盘和并行文件系统。如果数据集比较小,计算节点的本地盘足够放下整个数据集,那训练任务完全就可以把数据先存到本地盘上,然后基于本地盘来做计算。在另外一些场景下面,本地盘的大小远远不够存放下整个数据集,那这个时候就需要一个规模更大的共享文件系统来做这个事情,这是并行文件系统要解决的问题。这个并行文件系统会有自己独立的集群,多租户共享,支持 RDMA 网络、NVMe SSD,软硬件都做了很多的优化,来保证在海量小文件场景下,能够有比较好的元数据性能和 I/O 性能。
第二类解决方案针对那些训练时长非常长、重复较少的一些训练,这类训练主要的要求是能够把数据源源不断地从存储底座读取出来,吞吐比延时更重要。这个时候很多业务的选择就是去直接访问存储底座,利用存储底座比较好的高吞吐能力,来服务计算。
在整个使用过程中,还面临一些关键的使用问题。例如,数据怎么在不同系统(存储底座和并行文件系统、存储底座和本地盘)之间做流转;在使用的过程中,怎么简化不同类型存储的挂载、卸载和初始化、容量分配等工作。这些工作对于不同的业务来说是一样的,内部的大规模分布式训练平台,为用户屏蔽掉了这些繁琐的步骤,让这些业务对整个存储系统的使用,变得非常的简单和高效。
3. 百度沧海高性能存储解决方案
在百度内部实践的基础上,孵化出了百度沧海存储在高性能计算领域的整体解决方案。这个解决方案,和百度内部的实践是一样的,由大容量、高吞吐、低成本的存储底座,和更快的运行时存储 PFS、RapidFS 组成。
对象存储已经是业界共识的云上数据湖的事实标准,满足存储底座的所有条件,同时还有丰富的生态。和原来百度内部实践的存储底座相比,百度智能云的对象存储 BOS 还具备分级存储和智能生命周期能力。这两个能力可以让数据根据访问频次等条件,自由地在不同成本的层级间流转,达到整体成本最优的状态。举个例子,现在经常要使用的一些数据可以放到标准存储里面,这样的话它在访问的时候速度是比较快的,随着这些数据逐渐转冷,可能很长时间都不会再用到,那就可以把这些数据通过生命周期策略,自动地往更低频、更廉价的存储分级去沉降,最后可以一直沉降到磁带介质的归档存储上,以此来达到一个访问性能、成本之间比较好的均衡。
运行时存储 PFS、RapidFS 的最大特点就是这两个产品是近计算部署的,主要目的是为了让它们能够达到最好的 I/O 性能。这两个系统还需要解决和对象存储数据湖之间的高效数据流转的问题,以及在调度平台上如何更简单地使用它们的问题。接下来简单地介绍一下这两个系统。
3.1 并行文件存储 PFS
PFS 是一个典型的并行文件系统,和业界的 Lustre、GPFS 这些系统在架构上是比较接近的。系统主要的一个特点就是整个 I/O 路径会非常的短,请求从内核态客户端出来之后,根据它的类型的,是元数据的请求还是 I/O 的请求,直接发给对应的元数据节点 MDS 或者数据节点 OSS 处理。这样,对于读 I/O 来说,I/O 路径只有一跳。这个是软件架构上的性能保证,在硬件上我们同样有一些保证。PFS 采用托管架构将系统部署到用户 VPC 的虚机或物理机上,让它在整个物理网络上和计算节点离得非常近,这里的物理网络可能是 RDMA 或高速 TCP。PFS 通过这些软硬件上的多重保证,来确保整个系统的性能是比较高的。
3.2 分布式缓存加速 RapidFS
RapidFS 跟 PFS 一个最大的差别就是,PFS 使用了独立的存储节点进行部署,对于客户来说,仍然有一些成本上的付出。但是对于一些小规模的训练,计算节点本地有一些冗余的内存资源、磁盘资源,假如能把这些资源利用起来,对客户来说,就不需要付出额外的经济代价,同时还能享受到比较好的性能。RapidFS 就是为了解决这样一类场景而实现的一个系统,它的定位是一个缓存加速系统,原理是将用户计算节点上的冗余资源,组织成一个小的 P2P 缓存来加速计算。
RapidFS 加速的能力主要来自于两个方面:
第一个加速效果来自层级命名空间(namespace)。命名空间在存储系统里负责组织文件和目录之间的关系以及保存属性信息,文件系统的元数据也是指这一部分。层级命名空间是 POSIX 使用的命名空间形式,就像一棵倒挂着生长的树,从根目录开始,每一个文件或目录都属于一个父目录。平坦命名空间是对象存储使用的命名空间,文件和目录彼此是平等独立的,不存在父子关系,这个设计可以让命名空间的扩展性能更好。对于用户来说,想要通过 POSIX 的方式(这是很常见的用法)去访问对象存储,会有很大的元数据操作的放大。为了解决这个问题,RapidFS 内置了一个高效的层级命名空间,来做 BOS 命名空间的缓存。
第二个加速效果来自数据缓存。针对于 BOS 上数据访问比较慢的问题,RapidFS 将比较热的数据缓存到用户提供的冗余内存和磁盘上面,这样等用户去访问的时候,访问路径很短。
3.3 高效数据流转
有了这两类运行时存储之后,需要解决怎么在这两个系统和存储底座之间做数据流转的问题。实际上我们是通过两种机制来满足的:
第一种机制是生命周期,这一机制跟对象存储分级存储体系类似。在一些场景如 HPC 中,业务的整个访问入口主要是文件系统,也就是 PFS。很多数据在 PFS 里产生之后,逐渐转冷,将这部分数据存储到到更低成本的系统或介质上是一个普遍诉求。在我们的方案里,PFS 可以通过生命周期的功能,把近期内不再使用的数据,自动地转移到对象存储里面,让用户能够把成本降下来。用户去访问的时候,PFS 又把数据自动地给加载回来。这样用户自己其实是不需要去关心数据到底是在对象存储还是在 PFS 里面,他只需要关心哪些目录需要开启生命周期功能。在我们的规划里,RapidFS 后续将推出的 Block 模式也具备类似的能力,访问入口在 RapidFS,热数据缓存在计算节点本地,数据的持久化和冷数据由对象存储负责。
另外一个机制是 Bucket Link。Bucket Link 的数据流走向跟生命周期正好是反向的。很多情况下,用户的数据实际上已经在对象存储里面了,例如自动驾驶这样的业务,它的数据是线下采集的一些路测数据,这些数据通过对象存储服务提供的工具上会传到对象存储里,训练时候的数据源实际上就是对象存储。但如果想要用 PFS 或者 RapidFS 来支撑训练,就需要高效地把数据搬过来。Bucket Link 要解决的就是这个问题,它本质上是将数据搬运的能力内置到了存储系统里面,用户只要通过一个很简单的命令,或者说一个界面的操作,就能够把 PFS 的一个目录或者 RapidFS 的一个命名空间,和对象存储里面的一个路径做一个绑定,这个绑定就是 Bucket Link。绑定后,PFS 和 RapidFS 可以自动地帮用户完成数据的加载,以及数据的预热。这样等到用户训练真正开始运行的时候,PFS 和 RapidFS 里的数据已经准备好了,任务直接可以运行。
3.4 统一调度
Bucket Link 的能力可以手动调用命令去使用,但是很多情况下,对客户来说更方便的使用方法是去结合作业调度器。前面我们已经提到了,现在越来越多的客户会使用K8s 作为他们的作业调度系统,因此我们选择将 Bucket Link 整合到 K8s 中。
业界有一个开源项目叫 Fluid,它可以将整个训练的过程分成了两个阶段,一个阶段是用来做数据加载,另外一个阶段才是用来做真正的训练。这两个阶段拆分之后,在不同的任务之间 pipeline 并发起来。
举个简单的例子,整个系统可能只有四张 GPU 卡,A 训练跟 B 训练都需要去用这四张卡来做训练,那在 A 训练跑 GPU 任务的时候,完全可以让 B 训练提前做数据预加载的工作,将数据提前预热到 PFS 或者 RapidFS 里。等到 A 训练任务完成的时候,就直接可以让调度器把 B 训练跑起来了。整体上看到的效果就是 B 的数据加载阶段被隐藏掉了,加载过程跟计算过程分阶段 pipeline 化了。对于那些训练任务很多的用户,GPU 等待时间变少了,利用率得到了很大的提高。
PFS 和 RapidFS 统一都支持了 Fluid,在使用上体验接近,可灵活替换。在这个基础上,我们也会支持一些很细分的策略。那些对 I/O 延时不太敏感,但对元数据比较敏感的一些训练,可以只让它加载元数据。对元数据和数据访问要求都比较高的一些训练,在加载元数据的同时预热数据。所有的这些技术手段,目的都是让用户感受到比较好的使用体验。
3.5 测试数据
我们来简单看一下 PFS 和 RapidFS 在实际支持用户训练时候的效果。在这个例子里,有三组数据,分别是基于 RapidFS、PFS、对象存储直接来做 GPU 训练。可以看出,当使用 RapidFS 或 PFS 使用 Bucket Link 做完数据预热之后,整个训练期间的 GPU 利用率直接打满。基于对象存储直接来做这个训练的话,中间很大一部分时间是消耗在数据的读取上,整个 GPU 利用率在一个非常低的水位上。通过这样一个实验,我们大致能够看到 RapidFS 跟 PFS 在高性能计算加速这一块的效果。
4. 客户案例
最后我们来介绍一个典型客户的案例。
大家都知道百度是国内最大的自动驾驶方案厂商,也具备将自动驾驶整体解决方案对外输出的能力。因此有一些造车新势力的企业,在百度智能云上使用自动驾驶的整体解决方案,其中就包含百度沧海·存储提供的解决方案。
在图示的案例里,客户的一些采集车线下做路测,不断地通过车上的摄像头去采集路况数据。这些数据通过百度智能云提供的一个叫“月光宝盒”的专门硬件存储下来。采集到的数据客户可以选择两种方式上传到对象存储 BOS 里面。第一种方式通过网络的方式来传输,这种方式的速度受限于网络带宽,实际上整个吞吐不太高。另外还有一种方式可能大家看来会是很原始,就是把通过物流把月光宝盒寄回来。
月光宝盒这个设备可以简单的理解为一个比较大的移动硬盘,当然它会比普通的移动硬盘盘数更多,可靠性更高。用户采集了一批数据之后,可以直接把月光宝盒邮寄到百度智能云的数据中心,再通过内部的网络把这些数据上传到对象存储 BOS。这样的解决方案,能够保证用户在 10 个小时之内能够完成 1PB 数据的上传,远比使用网络上传的方式要快很多。所以说这种方案虽然看起来可能比较原始,但是确实很高效。
客户将他的数据沉淀到对象存储 BOS 之后,基于这些数据来做后续的训练,PFS 就是主要用来支撑它整个 GPU 集群训练的产品。整个并行文件存储 PFS 集群大概是数 PB 容量,只有在训练的时候才会把需要的数据加载进来,高效支持了数千卡 GPU 集群的训练。
用户实际上还用了很多百度智能云提供的一些其它能力,包括在 IaaS 侧、PaaS 侧的BBC、BCC、MongoDB 等产品,以及百度智能云针对 AI 领域的一些 SaaS 服务。这些能力其实都是在百度内部经过大规模实践之后,才在百度智能云产品化出来的。
客户训练的结果又会反馈到路测的流程上,形成了一个完整的闭环,一轮轮地去做数据的采集、训练和方案的迭代。