简介
转载于:关于LLM和Serverless的过去,现在和未来。
作者:ServerlessLLM开源小组(本文主要由Yeqi Huang,Luo Mai和Yao Fu共同撰写)
开源项目地址:ServerlessLLM GitHub
在这篇文章中,我们将探讨 LLM 与 Serverless 技术的过去、现在和未来。在正式讨论前,不妨先思考几个问题:
- 从个人开发者到像 OpenAI 这样的巨头,企业通常会维持一定数量的服务器来支持业务,但在用户数量波动大的场景中,如何有效应对服务器的浪费与高峰需求?
- 随着 Apple Intelligence 的崛起,个人模型定制化与隐私保护需求日益增长,未来我们每个人是否都会拥有自己的定制化 LLM 来帮助完成日常任务?
为什么我们需要LLM时代的“滴滴打车”,甚至全球化的“Uber”?
我们大约在 2018 年首次接触到 Serverless,当时它还只是用于搭建个人博客的工具。在我看来,它的发展类似于汽车行业的变革:
- 买服务器部署就像买车,完全自主,但成本高昂;
- 租服务器像租车,简化了硬件维护,却存在资源浪费的风险;
- 购买 API 则像乘公交车,只用付出特定的服务成本。
随着业务复杂度增加,Serverless 以其按需计费、灵活弹性等优势逐渐流行。像“滴滴”这样的共享模式出现在云计算领域,按需使用并付费,解决了服务器闲置和高额维护的痛点。然而,Serverless 背后并不简单,它需要深厚的系统架构和软件开发知识。
关于 Serverless 的争议从未停息。一些文章指出,Serverless 在某些场景下并不好用,比如初创企业为了整合多个微服务,往往会面临复杂的维护问题。然而,异构计算和 AI 业务的出现为 Serverless 带来了新的活力,尤其是高性能 GPU 的按需租赁模式,可以帮助更多企业降低成本并获得强大算力。
2022 年,许多个人和企业尝试将大语言模型(LLM)落地,但大部分人无法准确评估这些技术的效果和成本。在爱丁堡,我们建立了一个研究小组,专注于 Serverless 与 LLM 的结合,目标是构建一个低成本、易于部署的定制化 LLM 解决方案。随着研究深入,我们发现 LLM 和 Serverless 是绝佳的搭档。传统计算往往需要复杂的 FaaS 函数编写,且难以满足性能需求,但 LLM 的兴起简化了这些步骤。用户无需再编写繁琐代码,而是通过灵活组合模型和系统组件来完成任务。我们只需优化模型启动、存储和数据通信,便可实现高效运行。
Serverless + LLM ,比想象中难
GPU + Serverless 乍看是完美组合,但在实际开始实施时,我们遇到了很多意想不到的挑战。正如我们同事 Yeqi 在一篇博客中提到的分析那样:
传统的 Serverless 业务中的一个重要环节是 cold boot,也就是常说的冷启动时间。简单来说:当一个应用场景中的用户数量增长超过现有机器的承载能力后,我们需要启动新的机器,配置上当前的业务程序去承载更多的用户。(当然,更准确的说法不是启动新的机器而是新的容器)
在经典的场景中:
Cold boot = 启动新容器的时间 + 容器和已有服务集群连接时间
但是,在 AI 场景中,我们的应用负载有了非常大的区别:
- 大型LLM检查点文件:模型本身在这种环境下是一个必须的超大文件,这部分下载需要耗费大量的时间
- 复杂的AI硬件:我们的容器中包含了 GPU 硬件,但是运行大模型的时候,我们真正用的并不是机器内存,而是 GPU 上的显存
- 复杂的启动过程:传统应用启动之后,我们应用可以直接运行;但是作为 AI 应用,我们需要将模型载入 GPU
换而言之,现在 AI 时代的大模型应用:
Cold boot = 启动新容器的时间 + 模型下载时间 + 模型载入内存时间 + 模型载入 GPU 时间 + 容器和已有服务集群连接时间
为了给出一个更加量化的具体感受,我们测试了一个比较流行的 Serverless GPU 方案:Ray Serve + PyTorch。 实验环境采用了:10 Gbps network, A5000 with PCIe 4.0, NVMe SSD。
Model | Download | Load | Token decode time | End-to-end |
---|---|---|---|---|
LLaMA-2-7B | 10.8 s | 4.8 s | 0.8 s | 20.1 s |
LLaMA-2-13B | 21.0 s | 9.5 s | 0.9 s | 34.5 s |
LLaMA-2-70B | 111.9 s | 48.0 s | 8.3 s | 173.7 s |
不难看出,绝大部分时间的开销都在模型的下载和加载上。现有的解决方案大致有三种:
- 多开(Oversubscription):提前启动足够多的 Serverless 服务等待客户,但这种方式价格明显不合适,而且会导致资源浪费。
- 使用 DRAM 作为缓存:空间有限,虽然之前我们认为这是最好的办法,但随着 grok 这种 600G 的模型出现,即使是 2TB 的超大内存,也只能存下几份模型副本。
- 增加高速外部存储服务:同样太贵,不适合长期使用。
对企业来说,部署模型最重要的永远是降本增效。增效的问题主要在模型本身,我们不是特别关心,所以如何降本就非常有讲究了。我们认为我们的机会在于利用 GPU Serverless 中被忽视的本地存储空间。GPU serverless 服务器厂商提供的服务只关心 GPU 本身,例如 banana 和 runpod 公司的服务,甚至只会暴露 GPU metrics 给客户。所以我们认为这些服务器有以下特征:
- 有 TB 级别的 DRAM
- 有几十 TB 级别的空闲 SSD
我们整篇工作其实都是在探讨如何更好地利用这些空间进行调度。主要有三点贡献:
- 开发了一个可以快速拉起模型到 GPU 的模型格式
- 发明了一种让模型推理可以快速迁移的方案
- 在上面的基础上,我们设计了一种调度模式,让 Serverless 场景下 end-to-end 的延迟最低
重新思考Checkpoint格式的设计
为什么我们要设计新的模型格式,是 torch 和 safetensors 不够好吗?
确实,在训练时,我们采用的是 Persist many, load few 的模式,因为我们需要将模型锁住,并不断更新梯度。然而在推理场景中,我们只关心加载的速度,属于 Persist once, load many 的模式。
为此,我们采用了解耦设计,将模型的初始化和 checkpoint loading 独立开:
这种设计的好处是,我们可以专注于各种优化手段以加速 checkpoint loading,从而追求极致的模型加载速度。
我当初加入项目时,就是负责研究这一块的 CUDA kernel 设计。最终,大家通过各种方案的组合,榨干了所有可能的带宽。结果上来看,确实达到了非常理想的效果,在许多模型上我们对比PyTorch和SafeTensor的高性能方案都取得了额外5-8倍的性能提升:
某种意义上,这项贡献可以独立于整个项目之外作为独立项目,在我们的试验环境下,模型加载速度提升了 5-8 倍。如果有更多的 PCIe 支持,我们甚至可以达到更高的加载性能。
和最近的 prefill/decoding 做区分的思路一样,不同负载的任务就应该使用差异化的框架和方案。compute-bound 和 memory-bound 的任务确实应该使用不同的计算范式。我们在模型加载中的思考也一样,训练和推理就是不一样的任务,所以,用一套模型格式可能不是那么聪明的选择。
为什么我们需要LLM推理的在线迁移?
首先介绍一下,什么是在线迁移(Live Migration)?
这里用一个例子直接回答这个问题(用一个动图来演示一下三种方案):
我们现在有两台服务器,第一台机器上,Model B 在 SSD 里;第二台机器上,Model B 在 DRAM 里,但第二台机器的 GPU 正在推理 Model A。现在我们希望找到一台机器去运行 Model B 的推理任务,那么哪一台更合适?
如果我们直接找空闲 GPU,即图中的方案 (a),我们需要等待模型从 SSD 中加载,这个时间开销巨大。如果我们采用抢占式方案执行,如方案(b),我们需要重新对 Model A 进行推理,打断带来的开销过高。
基于对 LLM 应用特性的观察,我们最终采用了 Live Migration 策略。简单来说,就是迁移 token,而不是暴力迁移 KV-Cache 或完全从头重推。
基于实验设备,我们做了一个简单的评估:
- 迁移 token:带宽和网络开销可以忽略不计。而且我们可以将已经处理完的 token 和原先的 prompt 合并成一个新的长 prompt,这样可以充分利用 GPU 设备的计算红利。
- 迁移 KV-Cache:会导致网络严重拥塞,而且每一步实际上都是在重新执行 decoding。
这两种方案的核心在于计算和通信资源的权衡。我们认为,通信资源的成本远远高于计算资源的成本。如果今天在公有云上购买计算资源,会发现按每个比特计算,数据传输的成本可能是GPU计算成本的几十倍甚至上百倍。因此,对于大多数企业和个人而言,迁移token能够显著节省网络资源,简化云网络的设计和负担。当然,最优的方案应该是计算与通信相结合。例如,当kvcache规模较小且网络带宽充裕时,迁移可能带来更大收益,这方面仍需进一步研究。
方案 (a):直接找空闲 GPU,需要等待模型从 SSD 中加载,时间开销巨大。
方案 (b):采用抢占式方案执行,需要重新对 Model A 进行推理,打断带来的开销过高。
- Live Migration:迁移 token,不暴力迁移 KV-Cache 或完全从头重推,利用 GPU 设备的计算红利,避免网络拥塞。
我们刚刚说了 Live Migration 好,但是也是在网速受限,且我们重新 prefill 的代价不太高的前提下。所以我们到底要不要做 live migration,实际上是由一个简单的线性模型来决策的。
我们在实验的过程中发现,live migration 的开销近似等于 prefill 的开销,而这部分和 token length 是线性相关的。
所以我们就可以简单地用一个算式来对我们的调度进行决策。我们最后在GPU集群调度器中实现了这个算式,让调度器可以很聪明地选择应该何时启动在线迁移,何时利用checkpoint locality从本地启动。
OSDI 2024 是我们的开始
自从 LLM 兴起后,越来越多的企业和机构开始尝试 Serverless + LLM 的组合。学术界有 Ion Stoica 团队开发的 Ray 及其衍生项目 KubeRay 和 Ray Serve;工业界则有 Banana.dev 和 Runpods 等。这一片“百花齐放”的景象让人振奋。
然而,在这繁荣的生态背后,我们一直忽视了冷启动(cold start)问题。借此机会,我们深入分析了模型训练和推理过程中对 checkpoint 格式的不同需求,定制化设计了合适的解决方案。我们花了一年时间精细打磨,最终使 Serverless + LLM 的体验更加顺滑易用。这一过程比想象中复杂得多。
OSDI 2024 只是我们项目的开端,坦率地说,许多细节仍有待完善,而且未来还有很多发展空间:
应用层面:目前,我们的研究聚焦于 LLM 推理这种相对简单的场景。然而,对于完整应用的部署,还有许多可迁移的场景尚未探索,例如微调模型和多模态模型。由于这些应用的特性,性能分析可能与 LLM 推理不同。比如,微调模型可能只需要关注 Lora 层,切换更为轻便;而多模态模型的 token 较长,或许不再适合 token 迁移。具体情况仍需进一步测试和分析。
存储层面:我们在文章中提到使用 local SSD 取得了理想效果,但这引出了另一个问题:每台机器的 SSD 应该预存哪些模型以优化初始加载?当机器闲置时,如何提前准备 SSD 内容以减少下一次 replica 的启动时间?这是一个接近生产环境的问题,需要了解用户行为和实际使用数据,才能深入研究。我们非常欢迎工业界的朋友提供宝贵的数据和建议。
开源,和大家一起努力!
一路走来,感触颇多。从最初很多人质疑 Serverless + LLM 的价值,到我们逐步理清思路,如今初见成果,并逐渐成为业界共识。这个过程让我们倍感自豪。自论文发表以来,字节跳动、华为、AMD、英伟达、微软、谷歌、亚马逊等众多公司,以及英国、德国的超算中心等全球 GPU 基础设施提供者都纷纷关注和了解了我们的项目。这让我们欣喜不已。
同时,我们深刻认识到,ServerlessLLM 不仅是科研和学术领域的产物,它应在开源生态下继续成长,吸引更多人参与开发。为此,我们将项目开源于ServerlessLLM GitHub,并持续维护和更新,欢迎大家加入讨论和开发。我们已建立了 Discord 和微信群组,期待大家的加入。如果有问题,欢迎通过 GitHub Issues 与我们联系,我们会积极回复。
在十月中旬,我们在爱丁堡举办了首届开发者大会,超过 50 位关注者现场参与,讨论了许多有趣的潜在应用。目前,我们正与许多开发者合作构建新功能,其中不少创新来自本科生和研究生,甚至来自我们意想不到的机构!这些功能将陆续推出。
ServerlessLLM 还有很大的提升空间。随着模型规模的扩展和异构设备的独立性增强,框架将更智能地选择硬件,使模型在最合适的设备上高效运行。我们的愿景是让每个人都能拥有属于自己的、多样化的智能代理,伴随终生,提供低成本、高稳定性的服务,成为你值得信赖的伙伴!