如何让硬件算力发挥最大效率,是所有资源运营商和用户非常关注的问题。百度作为一家领先的 AI 公司,拥有可能是业界最全的 AI 应用场景。
在这篇文章中,将和大家分享和讨论 GPU 容器虚拟化在复杂AI场景中的解决方案和厂内的最佳实践。
下面这张图片的左右两部分,在不同场合下已经多次展示过,放到这里主要想强调算力需求 —— 硬件算力的指数型增长,与真实应用场景中利用率偏低资源浪费之间的矛盾。
左边的部分是 OpenAI 统计的数据,从 2012 年以来,模型训练所需的算力每 3.4 个月翻一倍,截止到 AlphaGoZero 这类的大模型,训练算力已经增长了 30 万倍,并且这种趋势还在继续。一方面,随着算力需求的增长,主流 AI 加速单元计算性能也在以每两年翻一倍的速率增加。另一方面,资源利用效率却制约着硬件效能的充分发挥。
右边的部分是 Facebook 在 2021 年对数据中心 Machine Learning 负载分析的结果。大量的 AI 算力损失在故障、调度、时间片浪费、空间单元浪费等环节,真正的算力利用率不到 30%。我们相信,这也是国内各大基础设施运营商所面临的现状。
刚才提到在线集群不到 30% 利用率可能不符合很多同学的认知。在线的很多同学可能是模型和算法的开发者。我们普遍的认知是,在训练和测试过程中利用率可以保持很高的水平,甚至可以达到 100% 利用率。
但模型在生产环境上线,会受到很多约束,这些约束导致利用率远远达不到我们的预期。
下面我们用有限的篇幅总结一下主要的制约因素:
-
模型特点:每个模型网络不同,调用的底层算子组合不同,很大程度上会影响 GPU 的利用率。
-
服务 SLA:不同场景下的服务需要不同的 SLA,有的服务实时性要求较高,甚至需要严格控制在 10ms 以内,那么这些服务就不能通过增加 batchsize 的方式提升利用率,甚至 batchsize 只能为 1。
-
流量模式:不同模型算法服务于不同的应用场景,比如 OCR 识别,可能在工作期间被频繁调用。而语音识别则更多的在通勤时间或者娱乐休闲时才会被调用,这样就导致了一天中 GPU 利用率的峰谷波动。
-
优化效果:根据模型的迭代频率以及覆盖场景的不同,模型的优化粒度也不尽相同。可想而知,一个未经充分优化的模型利用率也很难达到较高的水平。
-
容量冗余:模型上线前都要经过详细的容量规划,最大流量是多少,是否需要多地域,在此过程中会预留难以忽略的容量冗余,这些冗余在平时也造成了算力的浪费。
在上面种种约束条件的制约下,真实生产环境的利用率可能是接下来我们要展示的。我们从复杂多变的在线生产环境中抽象出这几种利用率模式。
-
均值偏低型:如左上图,为一个真实的在线推理业务,由于模型特点和服务 SLA 的限制,GPU 的峰值利用率只有 10%,平均利用率会更低。
-
峰谷波动型:如左下图,是典型的在线推理业务的利用率模式,服务在白天会达到高峰,在深夜至第二天早上是利用率的低谷,全天平均利用率只有 20% 左右,低谷利用率只有 10% 不到。
-
短时激增型:如右上图,利用率曲线基本与左下图一致,但在夜间黄金时段会有两个明显的利用率高峰,高峰阶段的利用率高达 80%,为了满足高峰阶段的服务质量,该服务在部署过程中会预留不小的 buffer,资源平均利用率也刚刚超过 30%。
-
周期触发型:如右下图,是典型在线训练场景的利用模式,在线训练任务介于离线训练和在线推理之间,这是一种周期性批处理的任务。例如每 15 分钟会有一批数据到达,但这批数据的训练只需要 2-3 分钟,大量的时间 GPU 处于闲置状态。
AI应用场景复杂多变,上面只是列举了四种典型场景。如何在复杂场景中,平衡业务性能与资源效率,是我们在 GPU 虚拟化中遇到的第一个挑战。
GPU 虚拟化过程中我们面临的第二个挑战就是缺乏完善的 GPU 隔离与混布机制。
我们以目前主流的 NVIDIA GPU 为例。典型的 AI 软硬件生态都分为这样几个层次 ——应用 & 框架层,运行时层,驱动层,硬件层。
首先最上层是用户的应用,这里包含了各种常见的框架 PaddlePaddle、TensorFlow、PyTorch 等等。在应用层之下是硬件提供商封装的 API 接口层,包含各类常用算子库与硬件运行时访问接口。在这层 API 接口之下,是与硬件沟通的驱动层,该层位于内核态,是直接与设备沟通的软件接口层。位于最底层是真正的 AI 加速硬件,负责算子的执行。
传统的虚拟化方案,都会结合驱动内核态以及硬件虚拟化逻辑实现。这两个层次是硬件提供商最核心的 IP,一般是闭源的。后续会提到,当前 GPU 原生的的隔离机制在灵活性和分配力度上都无法满足云原生场景下的使用需求。
除了隔离机制,现有的混布机制也很难满足复杂场景的需求,我们看到业界有很多共享调度的开源方案,这些开源方案只是从资源的层面把两个任务简单的调度到一张卡上。在实际场景中,简单的共享会造成业务之间相互影响,长尾延迟甚至吞吐的恶化导致简单共享无法真正应用于生产环境。
在上文利用率模式分析一节我们看到不同的业务,不同的场景下,利用率模式都不尽相同。如何抽象业务场景,定制混布方案,是生产环境落地的关键。
为了让大家更全面地了解 GPU 的发展以及虚拟化历史,这里我们用一张图来展示 GPU 虚拟化发展史。
GPU 应用于通用计算最早可以追溯到 G80 时代的 Tesla 架构,是第一代实现统一着色器的架构,用通用处理器 SM 替代了原来的顶点、像素管线分离的图形图像处理器。
百度最早引进的 GPU 可以追溯到 Fermi 架构。从这个时间点开始,业界就出现了一批虚拟化方案,其中大部分以 API 劫持为主。这里的典型代表是 rCUDA,该项目最初由学术团体维护,直到近期,还保持一定频率的更新和迭代,但看起来以学术研究为主,并没有在生产环境大范围使用。
百度大规模引入 GPU 是在 Kepler 架构,Kepler 架构开启了百度自研的超级AI计算机X-MAN 时代。X-MAN 1.0 首次实现单机 16 卡配置,可以在 PCIe 硬件层面实现 CPU 和 GPU 的动态绑定和灵活配比。受限于单卡性能,当时更多的考虑是扩展,而不是切分。
随后的 Pascal 架构、Volta 架构、Turing 架构性能有了飞速提升,这时虚拟化的需求日益显著起来。我们看到,最早从 Kepler 架构,NV 官方提供了 GRID vGPU 虚拟化方案,最开始主要是面向图形渲染和远程桌面场景。在 2019 年前后,针对 AI 和高性能计算场景也提供了解决方案。但这些方案都是基于虚机的,在 AI 场景中很少使用。
在 Ampere 这一代,NV 推出了 MIG 实例切分方案,该方案在硬件层面实现了 SM、MEM、L2 Cache 等多种硬件资源的切分,提供了良好的硬件隔离性能。但该方案从Ampere 架构开始支持,且对于卡的