1分离式架构
1.1 DistServe
DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving
DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving 讲的是一个将prefill和decoding分离的实现。
论文地址: https://arxiv.org/pdf/2401.09670
代码实现: https://github.com/LLMServe/DistServe
DistServe通过分离预填充和解码计算来提高大型语言模型(LLM)的性能。现有的LLM服务系统将这两个阶段放在一起,并批量处理所有用户和请求的预填充和解码计算。我们发现,这种策略不仅会导致强烈的预填充-解码干扰,还会将两个阶段的资源分配和并行计划耦合在一起。LLM应用程序通常强调每个阶段的个体延迟:预填充阶段的首个token时间(TTFT)和解码阶段每个请求的每个输出token时间(TPOT)。在严格的延迟要求下,现有系统必须优先考虑一个延迟,或者过度配置计算资源以同时满足两者。DistServe将预填充和解码计算分配给不同的GPU,从而消除了预填充-解码干扰。根据应用程序的TTFT和TPOT要求,DistServe为每个阶段定制了资源分配和并行策略的共同优化策略。DistServe还根据服务集群的带宽将这两个阶段放置在一起,以最小化由分解引起的通信。结果,DistServe在每个GPU上在TTFT和TPOT约束下提高了LLM服务性能的最大速率。我们的评估结果显示,在各种流行的LLM、应用程序和延迟要求上,与现有技术系统相比,DistServe可以提供7.4倍的请求量或12.6倍的更严格的SLO(Service Level Objective),并且仍然在90%以上的请求中满足延迟约束。
一个有效的LLM服务系统应该平衡这些需求,并最大化每个GPU的吞吐量,即在满足SLO达成目标(例如90%)的前提下可以提供的最大请求速率-更高的每个GPU吞吐量直接转化为更低的每个查询成本。由于预填充和解码阶段共享LLM权重和工作内存,现有的LLM服务系统通常将这两个阶段放在一起并通过批量处理预填充和解码步骤来最大化整个系统的吞吐量-跨所有用户和请求生成的token数每秒。然而,为了满足延迟要求,我们发现这些系统必须过度配置计算资源。为了看到这一点,图1说明了在使用现有系统[27]为13B LLM提供服务时,随着请求率的增加,P90 TTFT和TPOT如何变化,其中工作负载模式和两个延迟约束设置以模拟使用LLM为文章生成简短摘要。在满足90%的SLO达成率的情况下,单个A100 GPU的最大可实现吞吐量,受到TTFT和TPOT要求中较严格要求的限制,约为1.6个请求每秒(rps)。当每个阶段在不同的GPU上独立进行时,性能有显著差异,如橙色和绿色曲线所示,预填充阶段的每个GPU吞吐量为5.6 rps,解码阶段为10 rps。理想情况下,通过为预填充分配2个GPU和解码分配1个GPU,我们可以有效地提供模型的总体吞吐量为10 rps,或者每个GPU平均为3.3 rps,比现有系统高2.1倍。吞吐量差距主要源于预填充和解码的共同放置-两个具有非常不同计算特征和延迟要求的阶段。
也就是说在实现相同的TTFT的要求下,一个GPU单独prefill的情况下可以实现每秒5.6 个请求,而prefilling和decode都在一个GPU的llm 系统,只能达到1.6个rps.
在实现相同的TPOT的要求下,一个GPU单独decode的情况下可以实现每秒10 个请求,而prefilling和decode都在一个GPU的llm 系统,只能达到1.6个rps.
-
首先,放置在一起会导致强烈的预填充-解码干扰。预填充步骤通常比解码步骤花费更长的时间。当批量处理在一起时,批处理中的解码步骤会被预填充步骤延迟,显著延长其TPOT;同样,解码步骤的包含导致TTFT的显着增加,如图2所示。即使我们将它们分别安排,问题仍然存在,因为它们开始竞争资源。等待GPU执行的解码任务由于正在进行的预填充任务而增加了排队延迟,反之亦然。优先安排一个阶段可能会导致无法满足另一个阶段的延迟。
2. 预填充和解码计算在延迟要求和对不同形式并行性的偏好上有所不同。然而,放置预填充和解码,会耦合它们的资源分配,并阻止实现更适合满足每个阶段特定延迟要求的不同并行性策略。
通过将LLM推理的预填充和解码阶段分离,将它们分配给不同的GPU。我们的方法有两个好处。
-
首先,将每个阶段独立地在不同的GPU上运行可以消除预填充-解码干扰。
-
其次,它允许根据各自的延迟要求,通过量身定制的资源分配和模型并行性策略,独立地扩展每个阶段。虽然分解会导致在GPU之间通信中间状态,但我们展示了在现代GPU集群中,适当管理时,通信开销是微不足道的,并且分解显著提高了每个GPU的吞吐量。
作者构建了DistServe,一个通过分离预填充和解码阶段来优化吞吐量的LLM服务系统。给定TTFT和TPOT要求:
-
DistServe首先通过共同优化预填充和解码阶段的GPU分配和并行性策略,假设只提供单个模型副本,来独立地扩展每个阶段。这种优化确保最大化每个GPU的吞吐量,并根据各自的延迟要求可能为每个阶段分配不同数量的GPU和并行性策略。
-
DistServe通过复制将此分配扩展到多个实例,直到满足用户所需的流量率。
-
DistServe还具有一种算法,根据其分配方案和集群的带宽,将预填充和解码计算放置在一起,以最小化阶段之间通信的开销。
-
DistServe实现为LLM推理引擎的编排层。我们使用各种LLM对DistServe进行评估,根据三个重要的现实世界LLM应用程序调整工作负载:聊天机器人、编程助手和文档摘要。与现有解决方案相比,DistServe在延迟约束下可以提供高达4.48倍的请求量。
-
使用术语"实例"来表示管理完整模型权重副本的资源单元。当应用模型并行性时,一个实例可以对应多个GPU。需要注意的是,当我们将两个阶段分离到不同的GPU上时,每个阶段管理其自己的模型权重副本,从而产生prefilling实例和decode实例。prefilling实例在接收到请求后,仅执行该请求的prefilling计算以生成第一个输出令牌。然后,它将中间结果(主要是KV缓存)发送到decode实例,decode实例负责后续的解码步骤。由于decode计算通常具有较低的GPU利用率,我们可以为decode实例分配多个prefilling实例。这样可以批处理更多的解码作业,以实现更高的GPU利用率。分离预填充和解码自然地解决了两个阶段之间的干扰,并使每个阶段都能专注于其优化目标 - TTFT或TPOT。
调度策略:
DistServe的运行时架构如上图所示。DistServe采用简单的FCFS调度策略运行。所有传入的请求都到达一个集中式控制器,然后根据prefilling处理队列的最短的原则,分派到相应的prefilling实例进行处理,然后再分派到最负载最轻的解码实例进行解码。尽管这种设置简单,但是它经过了几个关键的增强,以适应现实世界工作负载的特点。