课程大纲
课程设计思路 (16周)
- 模块一:大语言模型及其服务概览 (第1-3周)
- LLM的基础知识入手,了解它们是什么,如何工作(特别是推理过程),以及为什么为它们提供服务是一个独特的挑战。这部分会为后续深入学习打下坚实的基础。
- 模块二:LLM服务的核心挑战剖析 (第4-6周)
- 这一模块将聚焦于报告中提到的核心挑战,例如负载的异构性与执行的不可预测性,服务等级目标(SLO)的保障难题 ,GPU资源碎片化问题 ,以及请求优先级的处理 [cite: 3, 25]。理解了“痛点”,我们才能更好地体会后续“解决方案”的巧妙之处。
- 模块三:LLM动态调度关键技术详解 (第7-10周)
- 这是课程的核心部分!我们将深入学习报告中阐述的各项关键技术。比如,神奇的运行时请求迁移(特别是KV缓存的高效迁移机制,想想Llumnix是怎么做的![cite: 8, 28]),各种面向LLM特性的智能调度策略(如基于预测的调度 [cite: 8, 32]、抢占式调度 [cite: 8, 36]),以及如何与自动伸缩协同工作 [cite: 8, 39]。
- 模块四:代表性系统架构与案例分析 (第11-13周)
- 理论结合实践才更有趣!我们会学习分布式调度系统架构设计 [cite: 8, 41],并重点分析一些代表性的系统,比如报告中详细讨论的Llumnix [cite: 45],还有像vLLM [cite: 53]、Orca [cite: 57] 等业界知名的系统,看看它们是如何运用动态调度技术来解决实际问题的。
- 模块五:前沿进展、未来展望与课程总结 (第14-16周)
-
最后,我们会一起探讨该领域的最新进展,例如多任务与多模型服务调度 [cite: 60, 61],并结合报告的结论 [cite: 79, 80, 81],展望未来可能的研究方向,比如更智能的调度决策、软硬件协同等。第16周则可以进行课程复习、项目展示或期末考试。
课程大纲
-
课程描述: 本课程旨在介绍大语言模型(LLM)推理服务的核心概念、挑战与前沿技术。学生将深入学习LLM推理的特性,理解传统服务方式的局限性,并重点掌握动态调度机制在提升服务效率、保障服务质量(QoS)及优化资源利用方面的原理、关键技术与系统实现,培养学生分析和解决LLM服务中复杂问题的能力。
学习目标: 完成本课程后,学生应能:
- 理解LLM的基本工作原理及其对推理服务提出的独特需求与挑战
- 阐述LLM服务中动态调度的核心挑战,如负载异构性、执行不可预测性、QoS保障、资源碎片化和请求优先级处理
- 详细描述并分析LLM动态调度的关键技术,包括运行时请求迁移、KV缓存管理、基于预测的调度、抢占式调度及分布式调度架构等
- 分析和评述代表性的LLM服务系统(如Llumnix, vLLM, Orca等)的设计思想与技术特点
- 探讨LLM动态调度领域的未来发展趋势和潜在研究方向
课程安排 (16周):
- 第1周:课程导论与LLM基础
- 课程目标、安排及评估方式介绍
- 什么是大语言模型 (LLMs)?发展历程与主要应用场景
- Transformer架构简介:自注意力机制、编码器-解码器模型
- LLM的训练与推理过程概述
- 第2周:LLM推理详解与服务初探
- LLM推理特性:自回归生成,逐Token计算
- 关键概念:KV缓存及其作用与挑战
- LLM推理服务的典型架构与组件
- 为什么需要专门的LLM服务系统?传统Web服务或DNN模型服务的局限性
- 第3周:LLM服务的性能指标与初步挑战
- 关键性能指标:延迟 (TTFT, TPTL)、吞吐量、并发量、成本
- 服务等级目标 (SLO) 的概念及其重要性
- LLM服务面临的初步挑战:高计算复杂度、大内存占用
- 传统调度策略简介 (如FCFS, Round Robin) 及其在LLM服务中的不足
- 第4周:核心挑战 (一): 负载异构性与执行不可预测性
- 请求特征的多样性:输入长度、输出长度、延迟敏感度等
- LLM输出长度的不可预测性及其对调度的影响
- 队头阻塞 (Head-of-Line Blocking) 问题剖析
- 第5周:核心挑战 (二): SLO保障与性能隔离
- 多租户环境下的QoS/SLO保障难题 [cite: 21]
- 性能干扰问题:计算资源与显存带宽的竞争 [cite: 21]
- 如何实现不同请求间的性能隔离?
- 第6周:核心挑战 (三): GPU资源碎片化与请求优先级
- GPU显存的外部碎片问题及其成因 [cite: 22]
- PagedAttention等显存管理技术简介 (如vLLM) [cite: 24]
- 请求优先级的定义与差异化服务需求 [cite: 25]
- 现有系统在优先级处理上的不足
- 第7周:关键技术 (一): 运行时请求重调度与迁移
- 动态调度的核心思想:运行时决策调整 [cite: 8]
- 请求迁移的动机:负载均衡、碎片整理、SLO保障等
- LLM请求迁移的关键:KV缓存的高效迁移机制 [cite: 28]
- 案例分析:Llumnix的实时迁移方法 [cite: 28]
- 第8周:关键技术 (二): 跨实例负载均衡与资源整合
- 利用请求迁移实现主动的跨实例负载均衡 [cite: 30]
- 通过请求迁移进行GPU显存碎片整理 [cite: 30]
- 讨论:迁移的成本与收益权衡
- 第9周:关键技术 (三): 面向LLM特性的智能调度策略 (预测)
- 基于预测的调度优化思路 [cite: 32]
- 输出序列长度预测技术 (如使用代理模型) [cite: 32]
- 近似最短作业优先 (SJF) 或最短剩余时间优先 (SRTF) 调度策略的应用 [cite: 32]
- 案例:SSJF[cite: 32], ELIS[cite: 48], 基于学习排序的调度器 [cite: 33, 49]
- 第10周:关键技术 (四): 智能调度策略 (抢占、自动伸缩)
- 抢占式调度的必要性与机制 [cite: 36]
- 公平性保障:如何在抢占的同时避免“饿死”现象? [cite: 38]
- 动态调度与自动伸缩 (Auto-scaling) 的协同机制 [cite: 39]
- 案例:QLM的请求驱逐[cite: 37, 51], Llumnix辅助自动伸缩 [cite: 39]
- 第11周:关键技术 (五): 分布式调度系统架构
- 集中式调度的瓶颈与分布式调度的优势 [cite: 41]
- 典型的分布式调度架构:全局调度器与本地调度器 [cite: 41]
- 案例:Llumnix的分布式调度设计 [cite: 41]
- 其他体现分布式思想的系统 (如Orca[cite: 57], AlpaServe [cite: 59])
- 第12周:代表性系统与方法评述 (一)
- 深入分析 Llumnix 系统 [cite: 45]:设计目标、核心技术、实验效果
- 讨论 ServerlessLLM [cite: 46]:无服务器场景下的LLM推理与迁移
- vLLM [cite: 53] 与 PagedAttention:KV缓存管理的里程碑
- 第13周:代表性系统与方法评述 (二)
- Orca [cite: 57]:迭代级调度与连续批处理
- Sarathi-Serve [cite: 58] 与 DistServe [cite: 25]:预填充与解码阶段的解耦和优化
- QLM [cite: 51]:面向SLO的队列管理与全局调度
- 第14周:LLM服务的前沿进展
- 多任务与多模型服务调度 (如 DeltaZip[cite: 60, 76], MQLserve [cite: 61, 78])
- 面向特定应用(如多轮对话 [cite: 54, 56])或硬件(如FlashInfer [cite: 62])的优化
- 长上下文处理、RAG、MoE等新兴场景对调度的挑战
- 第15周:未来展望、伦理考量与课程复习
- LLM动态调度的未来研究方向:基于学习的决策、软硬件协同、绿色计算等 [cite: 79, 80, 81]
- 调度系统的可解释性、鲁棒性与大规模部署挑战 [cite: 81]
- LLM服务相关的伦理、公平性与可持续性讨论
-
课程重点内容回顾与答疑
第一周大纲
第一周:课程导论与LLM基础
核心目标:
- 明确课程的定位(理论研究型)、目标、学习路径及评估方式。
- 使学生对大语言模型(LLM)的定义、发展背景、核心能力及广泛应用建立清晰的认识。
- 初步理解Transformer架构的核心思想与关键组件。
-
对LLM的训练与(尤其是)推理过程有一个概要性的了解,为后续深入探讨服务挑战奠定基础。
第一部分:课程导论 (建议时长:20-30分钟)
- 欢迎与课程定位
- 课程名称:“大语言模型的高效服务:动态调度与系统优化”
- 欢迎致辞,激发学生对LLM服务这一前沿交叉领域的研究兴趣。
- 明确本课程的理论研究倾向:我们将更侧重于理解问题本质、理论模型、关键技术原理及前沿研究进展的分析与批判性思考。
- 课程目标与核心议题
- 概述通过本课程学生将获得的理论知识与研究能力(参考教学大纲中的学习目标)。
- 点明核心议题:LLM推理服务的独特挑战,以及动态调度机制如何从理论和技术层面应对这些挑。
- 课程结构与学习路径
- 简要介绍课程的五大模块及其内在逻辑。
- 强调核心参考资料:白欣宇同学的论文《大语言模型推理服务中的动态调度机制:研究进展与前沿探索》[cite: 1],它将作为我们许多讨论的起点和重要参照。
- 提及其他辅助性的经典论文或综述。
- 评估方式与学术期望
- 说明成绩构成:例如,课堂参与与讨论、文献阅读报告/评述、期中理论分析作业、期末研究型论文或深度分析报告。
- 强调主动学习、批判性思维和学术诚信的重要性。
- 为什么研究LLM服务?——理论与现实意义
- LLM作为人工智能领域近年来的突破性进展,其强大的能力深刻改变着诸多领域 [cite: 18]。
- 引出核心矛盾:LLM潜力巨大,但其高效、经济、可靠的服务面临严峻的理论和技术挑战 [cite: 18],这正是本课程的研究焦点。
第二部分:大语言模型(LLM)概览 (建议时长:50-60分钟)
- LLM的定义与特征
- 什么是大语言模型?—— 通常指包含数十亿乃至数万亿参数的深度学习模型 [cite: 18]。
- 核心能力:强大的自然语言理解、生成、与交互能力 [cite: 18]。
- 理论基础:基于海量文本数据训练,学习语言的统计规律与深层语义表示。
- 与传统NLP模型的区别:规模、通用性与“涌现能力”。
- LLM发展简史与主要流派
- 从统计语言模型到神经网络语言模型的演进。
- 里程碑式的架构:RNNs, LSTMs 及其局限。
- Transformer架构的诞生及其主导地位。
- 提及代表性模型家族(如GPT系列 [cite: 18]、BERT、LLaMA等)及其特点(简述,不作技术深究)。
- LLM的主要应用场景及其对服务的启示
- 文本生成、对话系统、代码辅助、搜索引擎等。
- 分析不同应用场景对服务需求的差异性,例如:
- 交互式应用(如聊天机器人)对首个Token延迟(TTFT)的高度敏感。
- 离线批量任务(如文档摘要)对整体吞吐量的关注。
- 引出思考:这种需求的多样性(即负载异构性)对服务系统的设计(尤其是调度策略)提出了哪些理论挑战?
第三部分:Transformer架构核心思想 (建议时长:50-60分钟)
- 背景:序列建模的挑战与传统方法的局限
- 长距离依赖问题。
- 并行计算的限制。
- Transformer核心理念:“Attention is All You Need”
- 摒弃循环结构,完全依赖注意力机制进行序列信息捕获。
- 概述其对并行计算和长距离依赖处理的理论优势。
- 关键机制:自注意力 (Self-Attention)
- 理论动机:模拟人类认知中对信息重要性的动态关注。
- 核心计算过程:Query, Key, Value 的概念及点积缩放注意力。
- 多头注意力 (Multi-Head Attention):从不同表示子空间捕捉信息的思想。
- 架构组件
- 编码器 (Encoder) 与解码器 (Decoder) 的基本构成与作用(重点关注解码器在生成任务中的角色)。
- 位置编码 (Positional Encoding):解决Transformer本身缺乏序列顺序感知的问题。
- 前馈神经网络 (Feed-Forward Networks)。
- 残差连接 (Residual Connections) 与层归一化 (Layer Normalization) 的作用:缓解梯度消失/爆炸,加速收敛,支持更深层网络。
-
(对于理论研究,可以探讨这些组件设计选择背后的数学或信息论原理,以及它们如何影响模型的表达能力和学习效率。)
第四部分:LLM的训练与推理过程概述 (建议时长:30-40分钟)
- LLM训练概览 (简述)
- 学习目标:通常是“下一个词元预测”(Next Token Prediction)。
- 训练数据:海量的文本语料。
- 主要阶段:预训练 (Pre-training) 与微调 (Fine-tuning)。
- (点到为止,核心是理解模型能力的来源,为后续推理服务中的模型特性理解做铺垫)。
- LLM推理过程详解 (重点)
- 自回归生成 (Autoregressive Generation):逐个词元生成输出,当前词元的生成依赖于先前所有已生成的词元 [cite: 18]。这是理解LLM推理服务复杂性的关键。
- KV缓存 (KV Cache):
- 定义:为避免重复计算,推理过程中需要缓存已生成词元的键(Key)和值(Value)向量(即中间状态)[cite: 18]。
- 重要性:极大影响推理效率。
- 挑战:KV缓存体积庞大且随生成长度动态变化,对GPU显存造成极大压力 [cite: 18]。这是后续课程中调度、迁移、资源管理等议题的核心痛点之一。
- 推理的计算密集与内存消耗特性 [cite: 18]。
- 解码策略简介:贪心搜索 (Greedy Search)、束搜索 (Beam Search)、采样 (Sampling) 等及其对生成结果特性(如多样性、一致性)的影响。
- 从基础到服务:引出课程核心
- 点明LLM推理的特性(如迭代计算、庞大的KV缓存状态 [cite: 20])是导致其服务极具挑战性的根本原因。
-
预告后续章节将深入探讨这些特性如何转化为服务系统中的具体难题 (如延迟、吞吐量、成本之间的权衡)。
第四部分
第四部分:LLM的训练与推理过程概述
4.1 LLM训练概览 (理论视角,保持简洁)
首先,我们简要了解一下LLM是如何“炼成”的。虽然我们的课程核心是推理服务,但训练过程决定了模型的“基因”,深刻影响着它在推理时的行为特征。
- 4.1.1 核心学习目标 (Learning Objective):
- LLM学习的核心机制是自监督学习 (Self-Supervised Learning)。这意味着模型主要从海量的、没有人工标注的文本数据中自己寻找学习信号。
- 其中最主要的任务,尤其是对于我们课程后续重点关注的生成式LLM而言,就是下一个词元预测 (Next-Token Prediction),也常被称为语言建模 (Language Modeling)。
- 从理论上讲,就是给定一段已经出现的文本序列,比如 $t_1, t_2, …, t_{k-1}$,模型的目标是学习一个概率分布,并从中准确地预测出紧随其后的下一个词元 $t_k$。形式化地说,就是最大化条件概率 $P(t_k | t_1, …, t_{k-1})$。
- 通过在巨量文本上不断重复这个看似简单的任务,模型能够逐渐学习到词汇知识、语法结构、句子间的连贯性、上下文的关联,甚至在某种程度上掌握了常识和一定的推理能力。这是非常强大的!
- 当然,还有其他的训练范式,比如像BERT模型那样使用的掩码语言模型(MLM),它会随机遮盖输入文本中的一些词元,让模型去预测这些被遮盖的词元。但对于我们课程主要讨论的、以生成文本为核心任务的LLM(如GPT系列),自回归的下一个词元预测是更主流的范式。
- 4.1.2 训练的基石:数据与计算资源 (Data and Computational Resources):
- 海量文本数据 (Massive Datasets): LLM的“养料”是规模惊人的文本数据。这里的“大”不仅仅指数量级(通常是TB级别甚至PB级别的数据,涵盖网页、书籍、代码、对话记录等),更重要的是数据的多样性。正是这种多样性,使得模型能够接触到语言在不同场景下的丰富表达,从而学习到更通用、更鲁棒的语言表示。
- 从理论上看,训练数据的分布直接决定了模型最终学到的知识范畴、能力边界,甚至可能包含并放大其中潜在的偏见。这是一个非常值得研究的理论问题。
- 巨大的计算需求 (Significant Computational Resources):
- 训练这些巨型模型(参数量动辄数十亿甚至上万亿)需要在同样巨大的数据集上进行,这意味着海量的梯度计算和参数更新。因此,这需要动用成百上千乃至上万块GPU或TPU,进行长达数周甚至数月的持续训练。这背后的能源消耗和成本也是非常可观的。
- 为了应对这种计算挑战,分布式训练技术是必不可少的,例如我们常听到的数据并行、模型并行、流水线并行等策略。
- 虽然分布式训练本身不是本课程的核心,但理解其复杂性,有助于我们认识到我们后续要“服务”的这些模型,其本身就是非常“沉重”的。
- 海量文本数据 (Massive Datasets): LLM的“养料”是规模惊人的文本数据。这里的“大”不仅仅指数量级(通常是TB级别甚至PB级别的数据,涵盖网页、书籍、代码、对话记录等),更重要的是数据的多样性。正是这种多样性,使得模型能够接触到语言在不同场景下的丰富表达,从而学习到更通用、更鲁棒的语言表示。
- 4.1.3 主流训练范式 (Key Paradigms):
- 预训练 (Pre-training): 这是LLM训练的第一阶段,也是最耗费资源的部分。模型在通用的、大规模的语料库上进行训练,目标是学习广泛的语言理解和生成能力。完成预训练的模型,我们通常称之为“基座模型”或“基础模型”(Foundation Model)。
- 理论上,预训练赋予了模型关于语言结构、世界知识和基本推理的广泛先验。
- 微调 (Fine-tuning): 在强大的预训练模型基础上,我们可以针对特定的下游任务(如特定领域的问答、特定风格的写作)或特定的数据分布,使用规模相对较小的、可能包含人工标注的数据集进行进一步的训练。这能让模型更好地适应具体应用场景的需求。例如,指令微调 (Instruction Fine-tuning) 就是通过包含“指令-输出”对的数据进行微调,让模型学会更好地理解和遵循人类的指令。值得注意的是,如何高效服务大量经过全参数微调(FMT)的模型,已经成为一个新的研究挑战 [cite: 60, 73]。
- 理论上,微调是在通用能力之上进行“专业化”的过程。但它也可能带来一些问题,比如“灾难性遗忘”(模型在学习新知识时忘记了部分旧知识)。因此,如何有效地管理和利用这些经过微调产生的“模型增量”(delta),也是一个有趣的研究点 [cite: 60, 73]。
- 预训练 (Pre-training): 这是LLM训练的第一阶段,也是最耗费资源的部分。模型在通用的、大规模的语料库上进行训练,目标是学习广泛的语言理解和生成能力。完成预训练的模型,我们通常称之为“基座模型”或“基础模型”(Foundation Model)。
- 4.1.4 训练对后续推理服务的影响:
- 总结一下,尽管我们课程的聚焦点在于推理服务,但我们必须认识到,训练阶段的种种选择——模型的具体架构、参数的最终规模、权重的分布特性等等——都将直接且深刻地影响到模型在推理阶段的计算特性、内存占用(比如我们稍后会重点讲到的KV缓存大小)、响应延迟和能够达到的吞吐量。可以说,训练的终点,恰恰是推理服务挑战的起点。
4.2 LLM推理过程详解 (理论核心,为服务挑战铺垫)
好,了解了模型是如何“学会”知识之后,我们现在来看模型是如何“运用”这些知识来生成文本,也就是推理过程。这部分是绝对的核心,因为它直接揭示了为什么LLM服务这么难。
- 4.2.1 自回归生成 (Autoregressive Generation) 的本质:
- 核心原理: 当LLM生成文本时,它不是一次性把所有内容都“吐”出来,而是逐个词元 (token) 生成输出序列 。大家可以想象成模型在写句子时,是一个词一个词地往外蹦。
- 更关键的是,每个新生成的词元都依赖于之前所有已经生成的词元以及用户最开始输入的“提示” (prompt)。
- 数学表述: 如果我们要生成一个词元序列 $T = (t_1, t_2, …, t_m)$,那么这个序列出现的概率可以被分解为一系列条件概率的连乘积:$P(T) = P(t_1 | \text{prompt}) \times P(t_2 | t_1, \text{prompt}) \times … \times P(t_m | t_1, …, t_{m-1}, \text{prompt})$。简单表示就是 $P(T) = \prod_{k=1}^{m} P(t_k | t_1, …, t_{k-1}, \text{prompt})$。
- 迭代特性: 这种严格的、一步接一步的顺序依赖性,是LLM推理过程最核心的特征,也是它与许多可以高度并行化计算的任务(比如图像处理的很多环节)的根本区别。这种特性天然地限制了在单个生成任务内部的并行处理能力。
- 4.2.2 “提示” (Prompt) 的角色与预填充 (Prefill) 阶段:
- 提示 (Prompt): 这是用户提供给模型的初始输入文本。它可以是一个问题、一段指令、或者一段需要补全的文字。提示为模型的后续生成设定了上下文和方向。
- 预填充阶段 (Prefill): 在模型开始逐个生成新的词元之前,它必须首先完整地“理解”用户给的这个提示。这个处理提示的过程,我们就称之为预填充阶段。
- 在这个阶段,模型会并行地(因为提示中的所有词元都是已知的)计算提示中每个词元经过Transformer网络后的注意力状态,并为它们生成初始的KV缓存——这个概念我们马上会详细解释。
- 预填充阶段通常是计算密集型的 [cite: 58],因为它要一次性处理整个(可能很长的)输入提示。但好消息是,因为提示内容是固定的,这里的计算在提示的词元维度上是可以高度并行化的。例如,DistServe系统会将预填充阶段的任务分配到特定的GPU组进行专门优化 [cite: 58]。
- 但这里也潜藏着一个问题:在预填充阶段,系统通常需要一次性为输入prompt中的所有token都分配KV缓存所需的显存空间。如果此时GPU显存的空闲空间是零散的(即外部碎片),即便总量足够,也可能无法满足这种对连续大块内存的需求,这依然是一个显著的问题。
- 4.2.3 KV缓存 (KV Cache): 推理效率的核心与服务挑战的源头:
- 理论动机与定义:
- 还记得我们讲Transformer架构时提到的自注意力机制吗?模型在计算每一个词元的新表示时,都需要将这个词元的Query向量与序列中所有(或其注意力窗口内的)词元的Key向量和Value向量进行交互。
- 现在想象一下,在自回归生成第 $k$ 个词元时,模型需要用到前面所有 $k-1$ 个词元(包括最开始prompt中的那些词元)的Key和Value向量。如果我们不把这些已经计算过的K、V向量存起来,那么每生成一个新的词元,都得把前面所有词元的K、V从头再算一遍!这对于长序列来说,将是灾难性的计算浪费。
- 为了解决这个问题,KV缓存就应运而生了。它的作用,就是存储在自回归生成过程中,所有已经处理过的词元,在Transformer的每一个注意力层计算得到的Key和Value张量。正如论文所说,为了避免重复计算,需要缓存大量的中间状态,即键值缓存(KV Cache)[cite: 18]。
- 工作机制:
- 首先,在预填充阶段,模型会为输入prompt中的所有词元计算出初始的K、V向量,并把它们存入KV缓存。
- 然后,在后续的逐个词元生成(通常称为解码阶段)过程中,每当模型生成一个新的词元,这个新词元的K和V向量也会被计算出来,并被追加 (append)到KV缓存的末尾。这样,当模型要预测下一个词元时,它就可以直接利用这个已经包含了到当前位置为止所有词元历史信息的、完整的KV缓存。Llumnix系统就巧妙地利用了KV缓存通常是“仅追加 (append-only)”的这一特性,来实现非常高效的请求迁移 [cite: 28, 45]。
- 对推理效率的积极意义: 毫无疑问,KV缓存通过避免海量的冗余计算,极大地提升了LLM的推理效率,是实现大模型实用化的关键优化之一。
- 对服务系统带来的严峻挑战 (理论层面的分析):
- 巨大的内存占用 (Memory Consumption): 这是KV缓存最直接、最令人头疼的问题。它的大小与诸多因素都成正比:包括当前处理的序列长度(也就是prompt长度加上已经生成的输出长度)、批处理请求的数量 (batch size)、模型本身的层数、每一层注意力头的数量、以及每个注意力头的维度等等。对于如今动辄百亿、千亿参数的大模型,以及可能很长的用户输入或模型输出,KV缓存动辄会占用几十GB甚至更多的GPU显存。正如论文指出的,KV Cache的体积庞大且随生成长度动态变化,对GPU显存造成极大压力 [cite: 18]。在很多情况下,KV缓存占用的显存甚至会超过存储模型参数本身所需的显存!
- 动态性与不可预测性 (Dynamic Size & Unpredictability): KV缓存的第二个麻烦之处在于它的“动态性”。每生成一个新的词元,KV缓存就会“长大”一点 [cite: 18]。更棘手的是,LLM最终会生成多长的输出,在请求刚到达系统时,我们通常是无法准确预测的 [cite: 18]。这就好比你不知道每个客人会点多少菜,但你又得提前为他们预留足够大的桌子和餐具。这种不可预测性使得对GPU显存的精确管理和高效规划变得异常困难,极易导致我们后续会详细讨论的资源碎片化问题(即有很多小的、不连续的空闲显存块,但无法满足新请求对大块连续显存的需求),从而降低GPU的整体利用率 [cite: 18]。
- 批处理 (Batching) 复杂化: 为了提高GPU的利用率,服务系统通常希望将多个用户的请求合并成一个“批次”(batch) 来统一处理。但是,如果一个批次中的不同请求,它们的输入长度不同、期望输出长度不同,那么它们各自需要的KV缓存大小以及增长速度也会千差万别。这就给如何在批处理中高效地分配和管理这些动态变化的KV缓存带来了巨大的挑战。针对这一点,像vLLM提出的PagedAttention技术,就借鉴了操作系统中虚拟内存分页的思想来管理KV缓存,它将KV缓存分割成固定大小的“块”(block),从而缓解了内存浪费,尤其是在解码阶段能够有效管理非连续的显存块,进而提高了批处理的大小和整体吞吐量 [cite: 24, 53]。
- 请求迁移的代价 (Migration Cost): 正如我们前面提到的,动态调度是提升LLM服务效率的关键技术方向。它可能需要在运行时将一个正在处理的请求从一个GPU实例迁移到另一个实例上(比如为了负载均衡,或者优先保障高优先级请求)。当一个请求被迁移时,它当前的核心状态——也就是它那可能非常庞大的KV缓存——也必须随之迁移。如果迁移KV缓存的过程非常缓慢或者开销巨大,那么动态调度的灵活性和收益就会大打折扣。再次提到Llumnix系统,它之所以能够实现高效的实时请求迁移,一个关键创新就是针对KV缓存的特性设计了高效的迁移机制 [cite: 28, 45]。
- 理论动机与定义:
- 4.2.4 解码策略 (Decoding Strategies) 简介及其理论影响:
- 定义: 当LLM在生成每一个词元时,它的最后一层(通常是一个Softmax层)会输出一个覆盖整个词汇表(vocabulary)的概率分布。这个分布告诉我们,在当前上下文中,词汇表中的每一个词元作为下一个词元出现的可能性有多大。解码策略,就是决定我们如何从这个概率分布中选择最终输出的那个词元。
- 常见策略:
- 贪心搜索 (Greedy Search): 这是最简单直接的策略。在每一步,它都直接选择当前概率最高的那个词元作为输出。这种方法非常高效,计算开销小,但缺点是容易“短视”,只顾眼前最优,可能会导致生成的序列陷入局部最优解,使得输出内容显得单调、重复,或者在需要更长远规划的语境中表现不佳。
- 束搜索 (Beam Search): 为了克服贪心搜索的“短视”问题,束搜索在每一步会同时保留(比如说)B个当前看起来概率最高的候选序列(我们称B为束宽,beam width)。在下一步,它会基于这B个序列分别扩展,然后再从所有扩展出的新序列中选出新的B个整体概率最高的序列。如此往复,直到生成结束标记或者达到最大长度,最后从这B个最终序列中选择整体概率最高的那一个作为输出。理论上,束搜索通过探索更广阔的搜索空间,能找到比贪心搜索更好的(即整体概率更高)的序列,从而提高生成质量。但它的计算开销大约是贪心搜索的B倍,而且有时仍然可能生成一些比较平淡或者不自然的文本。
- 采样方法 (Sampling Methods): 与前两种确定性搜索方法不同,采样方法引入了随机性,旨在让模型的输出更加多样化和富有创造性。
- Top-K采样: 在模型输出的概率分布中,只考虑概率最高的K个词元,然后在这K个词元中根据它们的相对概率进行随机采样。
- Top-P (Nucleus) 采样: 它不固定候选词元的数量K,而是选择一个概率阈值P(比如0.9),然后从概率最高的词元开始累加它们的概率,直到这个累加概率刚好超过P。这些被选中的词元构成候选集(称为”nucleus”),然后从这个动态确定的候选集中进行采样。这种方法的好处是,在模型对下一个词非常有把握时(即少数几个词占据了绝大部分概率),候选集会比较小;而在模型不太确定时(即概率分布比较平坦),候选集会比较大,从而允许更多可能性。
- 理论意义: 采样方法通过引入可控的随机性,能够让LLM的输出看起来更像人类的自然语言,避免了确定性搜索可能带来的重复和呆板。我们通常还会用到一个叫做“温度”(Temperature)的参数来调节采样时的概率分布:温度越高,概率分布越平滑,生成的文本越随机、越有“创意”(但也可能越不连贯);温度越低,分布越尖锐,生成结果越接近贪心搜索,越保守、越确定。
- 对服务的影响: 不同的解码策略在最终的生成质量、计算延迟、吞吐量之间存在着复杂的权衡。一个完善的LLM服务系统,可能需要支持用户选择不同的解码策略和参数,或者根据当前的服务等级目标(SLO)以及系统负载情况,动态地调整或推荐解码策略。
4.3 从理论到服务:连接推理特性与服务挑战
好了,我们已经详细剖析了LLM推理过程的内部机制。现在,让我们把这些理论知识与实际的LLM服务连接起来,看看它们是如何引发我们后续课程将要重点讨论的各种挑战的。
- 4.3.1 推理是LLM服务的核心瓶颈与优化焦点:
- 大家要明确一点,LLM服务的核心工作负载,几乎全部来自于执行用户请求驱动的推理任务。正如我们引用的论文开篇就指出的,LLM的推理服务,也就是将预训练好的大模型部署为在线服务,响应用户请求并生成结果,已经成为释放其潜能、连接模型与实际应用的关键环节 [cite: 18]。
- 因此,推理过程的效率(比如响应有多快,单位时间能处理多少请求)和成本(比如需要多少GPU资源,耗费多少电力)直接决定了一个LLM服务的用户体验好坏和商业上的可行性。论文也提到,LLM推理固有的特性,共同导致了其在实现低延迟、高吞吐和满足服务等级目标(SLO)方面面临巨大困难 [cite: 18]。
- 4.3.2 推理过程的计算与内存特征总结 (理论视角):
- 我们可以将一次典型的LLM推理请求(尤其是包含较长prompt或期望较长输出的)大致划分为两个主要阶段,它们具有不同的计算和内存访问特征:
- 预填充阶段 (Prefill): 如前所述,这个阶段主要是处理输入的prompt,生成初始的KV缓存。它的特点是计算密集型 [cite: 58],因为涉及到对prompt中所有token的大量并行计算。但好消息是,这部分的并行度较高。然而,它需要一次性为整个prompt分配可能很大的KV缓存空间 [cite: 24],这对内存管理提出了要求。
- 解码阶段 (Decoding / Autoregressive Generation): 这个阶段是逐个生成输出token。它的主要瓶颈通常是内存带宽受限,因为每生成一个token,都需要从GPU显存中读取庞大的模型参数和不断增长的KV缓存,并将新的KV状态写回显存。同时,由于自回归的特性,这个阶段的并行度(在单个序列的生成上)受到很大限制。DistServe系统就将解码阶段分配到不同的GPU组,并特别针对其访存密集的特性进行了优化 [cite: 58]。
- 总结来说,LLM本身巨大的参数量,以及在推理过程中动态变化且同样巨大的KV缓存,共同构成了对硬件资源(特别是GPU的计算能力、显存容量和显存带宽)的极端需求 [cite: 18]。
- 我们可以将一次典型的LLM推理请求(尤其是包含较长prompt或期望较长输出的)大致划分为两个主要阶段,它们具有不同的计算和内存访问特征:
- 4.3.3 为后续章节的核心挑战与技术奠定理论基础:
- 请大家务必记住,我们今天详细讨论的LLM推理的这些固有特性——比如严格的自回归生成方式 [cite: 18],庞大且动态增长的KV缓存 [cite: 18],以及预填充与解码阶段的异构性——正是我们后续课程中将要深入探讨的LLM服务所面临的诸多核心挑战(例如,响应延迟高、系统吞吐量低 [cite: 5]、服务等级目标SLO难以得到可靠保障 [cite: 18]、GPU资源碎片化严重 [cite: 18]、不同用户的请求优先级难以有效处理 [cite: 7]等等)的根本技术原因。
- 举几个例子来帮助大家理解这种关联:
- 论文中提到,LLM服务请求在输入长度(prompt长度)、期望输出长度、计算资源需求以及延迟敏感度等方面表现出高度的异构性 (Heterogeneity),并且单个请求的实际执行时间(尤其是最终会生成多少个token)在请求到达时往往是不可预测的 (Unpredictability)。这些特性直接源于LLM的应用多样性和自回归生成的本质,它们使得传统的、基于先验知识的静态调度策略(比如固定批处理大小)难以有效应对,很容易导致请求长时间排队或者资源浪费 [cite: 18]。
- 我们反复强调的KV缓存的巨大内存压力,是导致GPU显存产生外部碎片的主要诱因之一,这会严重影响GPU显存的实际有效利用率 [cite: 22]。
- 由于每个请求的输入prompt长度不同,后续生成的token数量也不同,导致它们的KV缓存状态(大小、增长速度)千差万别。这使得将多个请求有效地合并成批次进行处理(以摊薄计算开销、提高硬件利用率)变得非常复杂。
- 因此,对这些底层机制和原理的深刻理解,是我们接下来学习和研究更高级的服务优化技术,比如动态调度、资源优化、智能预测等的理论基石。动态调度机制的核心思想,就是在系统运行时,依据实时的负载状况、资源利用率、请求特性以及模型执行状态等动态信息,灵活地调整调度决策和资源分配策略,从而克服静态或简单调度策略的局限性,更好地适应LLM服务负载的动态变化和不可预测性 [cite: 18]。
结论/过渡 (2分钟):
好了同学们,今天我们详细地剖析了LLM的训练和推理过程。我们知道了LLM是如何学习的,更重要的是,我们深入了解了它们在生成文本时,尤其是自回归生成和KV缓存管理这两个方面,所展现出的独特计算和内存行为模式。大家应该已经体会到,KV缓存既是提升推理效率的功臣,也是给服务系统带来巨大麻烦的“双刃剑”。
希望大家课后可以进一步思考:面对LLM推理这种如此独特且苛刻的计算和内存行为模式,我们沿用过去服务传统应用(比如Web服务,甚至传统的深度学习模型服务)的那些架构和调度策略,会遇到哪些几乎无法克服的障碍呢?
带着这些思考,我们将在下周的课程中,正式深入地剖析LLM服务化具体面临的各项核心挑战,并开始审视学术界和工业界为了应对这些挑战,已经提出和正在探索的各种解决方案及其不足之处。
今天的课就到这里,感谢大家的聆听!
第二周大纲
好的,同学们,我们开始第二周的课程。
在第一周,我们对大语言模型(LLM)有了初步的认识,了解了它们的基本构成(Transformer架构)以及训练和推理的核心过程。特别是,我们详细探讨了自回归生成和KV缓存这两个对于理解LLM推理至关重要的概念。
本周,我们将首先回顾并深化对LLM推理特性的理解,并重点探讨这些特性对服务系统的具体影响。然后,我们会初步探索LLM推理服务的典型架构与核心组件。最后,也是非常关键的一点,我们会讨论为什么我们需要专门为LLM设计的服务系统,以及传统的Web服务或通用DNN模型服务系统在面对LLM时有哪些局限性。这将为我们后续几周深入学习LLM服务的核心挑战以及动态调度等关键技术打下坚实的基础。
第二周:LLM推理特性回顾及其对服务的影响,LLM服务系统初探
第一部分:回顾并深化理解LLM推理特性及其对服务的影响 (建议时长:40-50分钟)
- 1.1 关键概念回顾 (源自第一周内容):
- 自回归生成 (Autoregressive Generation): 我们再次强调,LLM是逐个词元 (token) 生成输出的,每个新词元的产生都依赖于之前所有已生成的词元和用户输入。这是一个严格的顺序依赖过程。
- KV缓存 (KV Cache): 为了避免在生成每个新词元时重复计算所有先前词元的注意力状态(Key和Value向量),系统会缓存这些中间结果。这个缓存就是KV缓存。它对于提升推理效率至关重要,但同时也带来了巨大的挑战。我们知道它的主要特性包括:
- 目的是避免冗余计算。
- 在生成过程中通常是“仅追加”的 (append-only) [cite: 28]。
- 其大小会随着生成序列的增长而动态变化。
- 它会消耗大量的GPU显存,通常比模型参数本身还要多 [cite: 18, 3]。
- 1.2 自回归生成对服务系统的影响:
- 延迟的敏感性与构成 (Latency Sensitivity & Composition):
- 对于用户而言,LLM服务的延迟感知主要有两个方面:
- 首个词元生成时间 (Time To First Token, TTFT): 指从用户发送请求到接收到第一个输出词元的时间。TTFT的高低很大程度上取决于处理输入提示(即预填充阶段)的效率。对于交互式应用,如聊天机器人,用户对TTFT非常敏感,过高的TTFT会带来明显的卡顿感。
- 词元间延迟 (Time Per Token Latency / Inter-Token Latency): 指生成后续每个词元所需的时间。这个延迟直接影响用户阅读生成内容时的流畅感。
- 理解这两种延迟的来源和影响,对于服务系统的优化至关重要。
- 对于用户而言,LLM服务的延迟感知主要有两个方面:
- 顺序生成的瓶颈 (Sequential Bottleneck):
- 由于自回归的特性,在生成一个单一序列时,词元之间存在严格的依赖关系,这使得并行化生成单个序列的内部过程变得非常困难。虽然可以在批处理层面并行处理多个请求,但每个请求的生成过程本质上还是串行的。这对单个请求能达到的最大吞吐量(或最小延迟)构成了理论上的限制。
- 可变的请求与生成长度 (Variable Request & Generation Lengths):
- 用户输入的提示长度各不相同。更重要的是,模型最终会生成多少个词元,在请求到达时往往是不可预测的 [cite: 18]。这种不可预测性给服务系统带来了巨大的麻烦,例如:如何为请求预留恰当的计算资源和内存?如果预留过多则浪费,预留过少则可能导致请求失败或需要重新调度。
- 延迟的敏感性与构成 (Latency Sensitivity & Composition):
- 1.3 KV缓存对服务系统的影响:
- 显存成为首要资源瓶颈 (Memory as a Primary Resource Constraint):
- 正如我们上周强调的,KV缓存可能消耗海量的GPU显存。在许多LLM服务场景下,显存容量往往比计算能力更早成为系统的瓶颈。
- 由于请求的KV缓存大小不一且动态变化,GPU显存极易产生外部碎片 [cite: 3, 22],即有很多小的、不连续的空闲显存块,但无法分配给需要较大连续显存的新请求(尤其是其预填充阶段)。这大大降低了显存的有效利用率。
- 动态内存管理的复杂性 (Dynamic Memory Management Complexity):
- 一个LLM服务系统需要同时处理大量并发请求,每个请求都有其独立的、动态增长的KV缓存。系统必须能够高效、精细地分配、跟踪、回收这些KV缓存占用的显存,并在显存不足时做出合理的决策(例如,拒绝新请求、抢占低优先级请求,或将某些请求的KV缓存置换到CPU内存甚至磁盘)。
- 批处理的挑战 (Batching Challenges):
- 为了提高GPU利用率,将多个请求打包(batching)处理是常用手段。但由于每个请求的KV缓存状态(当前大小、历史内容)和未来的增长趋势都可能不同,如何智能地组合请求以形成高效的批次,同时确保KV缓存不会冲突或溢出,是一个非常复杂的问题。这预示了我们后续会讨论的vLLM及其PagedAttention等内存管理技术的重要性。
- 请求的有状态性 (Stateful Nature of Requests):
- KV缓存实质上是LLM生成请求在特定时间点的完整“状态”。这意味着LLM推理请求是有状态的。这与许多传统的无状态Web服务(每个请求都可以被独立处理,不依赖先前请求的状态)有本质区别。请求的有状态性,使得负载均衡、请求迁移、故障恢复等机制的设计变得更加复杂。例如,当Llumnix系统要迁移一个请求时,它必须高效地迁移其KV缓存状态 [cite: 28]。
- 显存成为首要资源瓶颈 (Memory as a Primary Resource Constraint):
第二部分:LLM推理服务的典型架构与核心组件 (建议时长:50-60分钟)
了解了LLM推理的特性及其对服务的影响后,我们来看看一个典型的LLM推理服务系统是如何构建的,它通常包含哪些核心组件。
- 2.1 LLM服务系统的高层目标:
- 一个设计良好的LLM服务系统,其核心目标通常包括:
- 低延迟 (Low Latency): 快速响应用户请求,无论是TTFT还是词元间延迟。
- 高吞吐量 (High Throughput): 单位时间内能成功处理尽可能多的请求或生成的总词元数。
- 高资源利用率 (High Resource Utilization): 充分利用昂贵的GPU等硬件资源,避免闲置。
- 成本效益 (Cost-Effectiveness): 在满足性能目标的前提下,尽可能降低服务成本。
- 服务等级目标保障 (SLO Adherence): 能够为不同用户或应用场景提供可预期的、有保障的服务质量 [cite: 18, 3]。
- 一个设计良好的LLM服务系统,其核心目标通常包括:
- 2.2 核心组件及其交互流程 (概念层面):
- 我们可以想象一下一个用户请求从进入到获得结果的完整旅程,这其中会经过以下主要组件:
- 请求网关/路由器 (Request Gateway/Router):
- 这是用户请求的入口。它负责接收所有来自客户端的请求。
- 通常会执行一些基础的预处理工作,如身份验证 (Authentication)、权限校验 (Authorization)、请求限流 (Rate Limiting) 等,以保护后端服务。
- 在更复杂的系统中,它可能还会根据请求的类型、用户ID或优先级等信息,进行初步的路由决策,将请求导向不同的处理集群或队列。
- 请求批处理/调度单元 (Request Batching/Scheduling Unit):
- 这可以说是整个LLM服务系统的“大脑”。它负责收集到达的请求。
- 核心功能是做出智能的决策:哪些请求应该被处理?应该在什么时候处理?应该分配到哪个具体的模型实例或GPU工作单元上进行处理?
- 在做决策时,它需要综合考虑多种因素,例如:请求的优先级、请求声明的或预测的服务等级目标(SLO)、当前各个模型工作单元的负载情况、GPU的显存和计算资源状况、以及不同请求的KV缓存状态是否适合合并成一个批次以提高效率等等。
- 我们本课程的核心主题——动态调度——的绝大部分逻辑就实现在这个组件中。
- 模型工作单元/推理引擎 (Model Workers/Inference Engines):
- 这些是实际执行LLM模型推理的计算单元,通常是搭载了高性能GPU的服务器实例。
- 它们负责装载LLM的模型权重,并执行我们前面讨论过的预填充 (prefill) 和逐词元解码 (decoding) 这两个核心计算阶段。
- 同时,它们也需要为当前正在处理的请求管理其对应的KV缓存。
- 像vLLM [cite: 24, 53]、Orca [cite: 57, 83] 这样的知名LLM推理框架,其核心就是提供了非常高效的推理引擎实现。
- KV缓存管理器 (KV Cache Manager):
- 这个组件的功能非常关键,它通常与推理引擎紧密集成,或者作为其内部的一个重要模块。
- 它专门负责GPU显存中KV缓存的分配、跟踪、回收。在更高级的系统中,它还可能实现更复杂的优化策略,例如像vLLM的PagedAttention那样,通过分页机制来更灵活地管理非连续的显存块 [cite: 24, 53],或者在显存极度紧张时,将一些不活跃的KV缓存暂时“交换”到CPU内存甚至磁盘。
- 模型管理/编排单元 (Model Management/Orchestration):
- 在实际的生产环境中,服务系统可能需要同时支持多种不同的LLM模型,或者同一个模型的不同版本。这个组件就负责这些模型的生命周期管理,包括按需从模型库中加载指定的模型到GPU工作单元上,或者在模型不再需要时将其卸载以释放资源。
- 它还可能与自动伸缩 (auto-scaling) 机制联动 [cite: 39, 40],根据实时的请求负载动态调整运行特定模型的GPU工作单元的数量。
- 监控与日志系统 (Monitoring and Logging):
- 任何一个健壮的服务系统都离不开完善的监控和日志。它负责收集关于系统运行状态的各种指标数据,例如:请求的平均延迟和吞吐量、GPU的利用率(计算、显存、带宽)、KV缓存的命中率和占用情况、调度决策的执行效果、以及任何发生的错误或异常。
- 这些数据对于系统的日常运维、性能瓶颈分析、故障排查、以及持续优化调度策略和服务质量至关重要。
- 请求网关/路由器 (Request Gateway/Router):
- 我们可以想象一下一个用户请求从进入到获得结果的完整旅程,这其中会经过以下主要组件:
- 2.3 常见的架构模式 (简述):
- 在调度器的设计上,有集中式调度器(一个全局的“大脑”负责所有决策)和分布式调度器(决策压力分散到多个层面或节点)两种主要模式。例如,我们后续会详细学习的Llumnix系统就采用了一种包含全局调度器和实例本地调度器的分布式调度架构 [cite: 41],以提升可扩展性和响应能力。
- 从整体服务架构来看,一种常见的模式是采用无状态的前端服务集群(负责接收请求、初步处理和与调度器交互)配合有状态的后端推理工作单元集群(负责实际的模型计算和KV缓存管理)。
第三部分:为什么需要专门的LLM服务系统?传统服务方式的局限性 (建议时长:30-40分钟)
理解了LLM推理的独特性和典型服务架构后,一个自然的问题是:我们为什么不能直接用现有的传统Web服务架构或者通用的DNN(深度神经网络)模型服务框架来部署LLM呢?答案是,传统方法在面对LLM的特殊挑战时,往往力不从心。
- 3.1 传统Web服务架构的局限性 (例如,典型的I/O密集型应用服务):
- 传统的Web服务(比如电商网站的后端、社交媒体的信息流服务等)通常是为处理大量相对轻量级、短时、且无状态的并发请求而设计的。它们的瓶颈往往在I/O(网络、磁盘)而不是计算。
- 这类服务的请求处理逻辑通常比较简单和统一,可以很容易地通过增加更多相同的服务实例来进行水平扩展。
- 面对LLM的局限性:
- 无法有效管理有状态的重计算: LLM推理,特别是其依赖KV缓存的特性,是高度有状态的。传统Web服务架构缺乏对这种大规模、动态变化的计算状态(KV缓存)进行高效管理和优化的机制。
- 不适应GPU密集型负载: LLM推理是典型的GPU计算密集型和显存密集型任务,而传统Web服务架构通常不直接管理和调度GPU资源。
- 对复杂批处理和调度需求支持不足: 它们通常采用简单的轮询或基于负载的请求分发,无法满足LLM服务对精细化批处理、优先级调度、以及基于KV缓存状态的协同调度等复杂需求。
- 3.2 传统DNN模型服务框架的局限性 (例如,用于图像分类、目标检测等模型的服务):
- 相比通用的Web服务,传统的DNN模型服务框架(如TensorFlow Serving, TorchServe的早期版本)确实更接近LLM服务的需求,因为它们本身就是为部署和运行深度学习模型而设计的。
- 它们通常能够处理模型的加载、GPU资源的使用、以及一定的请求批处理。
- 但是,这些框架在设计之初,主要面向的是像图像分类这样的传统DNN模型。这些模型的推理过程通常具有以下特点:
- 请求通常是无状态的:每个输入(如一张图片)都独立地产生一个输出(如分类标签),模型不需要为同一个用户或会话的连续请求保留状态。
- 输入和输出的数据大小相对固定和可预测。
- 批处理相对简单:因为请求的计算特征比较相似,可以将它们简单地堆叠起来进行批处理。
- 面对LLM的局限性:
- 对自回归生成的特性支持不足: 传统DNN服务框架并非为LLM这种逐词元迭代生成的自回归特性而专门设计。它们可能缺乏对这种长序列、多步骤生成过程的有效管理和优化。
- KV缓存管理机制的缺失或简陋: 这是最核心的短板。传统DNN模型通常不需要像LLM的KV缓存这样巨大、动态且对性能至关重要的中间状态缓存 [cite: 18, 3]。因此,这些框架缺乏专门为高效管理KV缓存(如PagedAttention、KV缓存压缩、迁移等)而设计的复杂机制。正如你的论文中所述,传统的深度学习模型(DNN)调度策略,如简单的轮询分发或基于固定批处理大小的静态调度,难以直接适用于LLM服务,主要因为LLM服务负载的异构性和执行的不可预测性 [cite: 18]。
- 缺乏高级的批处理策略 (如连续批处理/迭代级批处理): 对于LLM,由于不同请求的序列长度和生成时间差异很大,简单的静态批处理(即等待一个批次完全填满或超时再开始处理)效率低下。它会导致GPU长时间等待最慢的请求完成,或者因为凑不齐一个大批次而使得GPU利用率不高。LLM服务需要更灵活的批处理策略,比如“连续批处理”(continuous batching) 或像Orca系统提出的“迭代级调度”(iteration-level scheduling) [cite: 57, 83],允许在批次执行过程中动态地加入新请求或移除已完成的请求。
- 对预填充和解码阶段的异构性处理不佳: 我们前面提到,LLM推理的预填充阶段(计算密集)和解码阶段(访存密集、迭代)具有显著不同的计算特征。传统的DNN服务系统通常不会对这两个阶段进行区分和专门优化。而像DistServe这样的现代LLM服务系统则会将这两个阶段解耦,并部署到不同的GPU组进行针对性优化 [cite: 30]。
- 难以应对高度的异构性和不可预测性: 论文明确指出,LLM服务请求在输入长度、期望输出长度、计算资源需求以及延迟敏感度等方面表现出高度的异构性,并且单个请求的实际执行时间(尤其是输出token数量)在请求到达时往往是不可预测的 [cite: 18]。传统DNN调度方法通常假设请求具有更强的同质性和可预测性,因此难以适应LLM服务的这些特点。
- 3.3 结论:LLM服务呼唤专门化的解决方案:
- 正是由于上述种种局限性,我们才迫切需要为LLM设计和构建专门的服务系统。
- 这些专门化的系统,其核心竞争力就在于它们能够深刻理解并针对性地优化LLM推理的独特特性,例如:
- 通过像vLLM的PagedAttention这样的技术高效管理KV缓存 [cite: 24, 53]。
- 实现如连续批处理、选择性批处理等高级批处理策略 [cite: 57]。
- 优化预填充和解码阶段的协同执行 [cite: 30, 57]。
- 以及最核心的,实现复杂而智能的动态调度机制 [cite: 3, 6, 80],以应对负载的动态变化、保障服务质量、并最大化资源利用效率。
总结与展望 (建议时长:5-10分钟):
- 回顾: 今天,我们复习并深化了对LLM推理特性(自回归生成、KV缓存)及其对服务系统深远影响的理解。我们还一起勾勒了典型LLM服务系统的架构蓝图,并详细论证了为什么传统的服务方式难以胜任LLM的部署需求,从而凸显了LLM服务系统专业化的必要性。
- 展望: 通过今天的学习,大家应该已经对LLM服务的复杂性和特殊性有了更直观的感受。这些复杂性和特殊性,具体表现为一系列核心的技术挑战。在下周的课程中,我们将正式进入这些“核心挑战”的深水区,逐一剖析你的论文第二章中提到的:负载的异构性与执行的不可预测性、服务等级目标(SLO)保障与性能隔离难题、GPU资源碎片化与高效利用、以及请求优先级与差异化服务需求等问题 [cite: 3]。理解了这些挑战,我们才能更好地欣赏后续课程中将要学习的各种动态调度技术是如何巧妙地应对它们的。
希望大家课后能再次回顾今天的内容,特别是KV缓存带来的影响以及传统服务系统的局限性,这将有助于我们更好地理解后续课程的重点。
今天的课就到这里。谢谢大家!
第三部分
好的,同学们。在了解了LLM推理的独特特性(尤其是自回归生成和KV缓存)以及一个理想的LLM服务系统应具备哪些核心组件之后,我们现在来探讨一个非常根本性的问题:为什么我们不能简单地使用现有的、已经很成熟的传统Web服务架构,或者即便是为其他类型深度学习模型设计的服务框架,来部署和运行大语言模型呢?为什么LLM服务需要专门化、定制化的系统?
这部分内容非常重要,因为它能帮助我们从对比中深刻理解LLM服务的特殊性和挑战性,从而认识到后续课程中我们将要学习的各种高级优化技术(如动态调度、精细化内存管理等)的必要性和创新性。
第三部分:为什么需要专门的LLM服务系统?传统服务方式的局限性 (建议时长:30-40分钟)
3.1 传统Web服务架构的局限性
首先,我们来看看我们日常接触最多的传统Web服务架构,比如支撑各类网站、电商平台、社交应用后端逻辑的那些系统。这些系统经过几十年的发展,已经非常成熟和高效。它们通常具有以下一些特点:
- 面向I/O密集型任务设计: 它们的主要工作是处理网络请求、读写数据库、访问缓存或文件系统等,计算本身通常不是瓶颈。
- 无状态 (Stateless) 为主: 为了便于水平扩展和提高容错性,Web服务的后端应用逻辑通常被设计成无状态的。这意味着服务器在处理一个请求时,不需要依赖该用户先前请求的任何上下文信息(如果需要,状态通常存储在外部的数据库或缓存中)。每个请求都可以被独立地路由到任何一个可用的服务实例上。
- 请求处理相对轻量和统一: 单个请求的处理时间通常较短(毫秒级或秒级),且不同请求的处理逻辑和资源消耗相对比较一致。
- 易于水平扩展: 当负载增加时,可以通过简单地增加更多的服务实例来分散压力。
那么,用这样的架构来服务LLM会遇到什么问题呢?
- 无法有效管理有状态的重计算负载: 这是最核心的矛盾。LLM推理,特别是我们反复强调的、依赖KV缓存的自回归生成过程,是高度有状态的。KV缓存就是这个请求在特定时刻的“状态”,并且这个状态在生成过程中不断变化和增长。传统Web服务架构缺乏对这种大规模、动态变化的计算状态进行高效管理和优化的内置机制。它们不擅长处理这种需要在单个请求的生命周期内持续维护和更新大量中间计算结果(即KV缓存)的场景。
- 不适应GPU密集型任务: LLM推理是典型的GPU计算密集型和显存密集型任务。而传统Web服务架构通常是基于CPU设计的,它们并不直接管理和调度GPU这种昂贵且特殊的计算资源。如果简单地将LLM推理逻辑嵌入到传统Web服务中,GPU资源的分配、复用、监控和优化都将成为大问题。
- 对复杂批处理和调度需求支持不足: 传统Web服务通常采用简单的请求分发策略,如轮询 (Round Robin) 或基于当前CPU/内存负载的均衡。它们无法满足LLM服务对请求进行精细化批处理(例如,根据KV缓存的相似性或请求的优先级来组合批次)、以及基于GPU资源状态和请求SLO(服务等级目标)进行复杂协同调度的需求。
简单来说,用设计来处理大量、快速、无状态、I/O密集型请求的Web服务架构,去承载LLM这种计算密集、内存消耗巨大、且高度有状态的推理任务,就像用一辆普通家用轿车去拉一整列火车的货物一样,力不从心且格格不入。
3.2 传统DNN模型服务框架的局限性
现在,我们可能会想,既然通用的Web服务不行,那么那些专门为部署其他类型深度学习模型(比如图像分类、目标检测、语音识别等)而设计的服务框架,比如TensorFlow Serving的早期版本或者一些通用的模型服务器,总该可以用来服务LLM吧?
这些传统的DNN模型服务框架确实比通用Web服务更进了一步。它们通常具备以下能力:
- 能够加载和管理深度学习模型。
- 支持使用GPU进行模型推理。
- 提供了一定的请求批处理 (batching) 功能以提高GPU利用率。
然而,这些框架在设计之初,它们所面向的“典型”深度学习模型与我们现在讨论的LLM之间,仍然存在着一些关键的差异。传统DNN模型(如用于图像分类的ResNet、VGG等)的推理过程通常具有以下特征:
- 请求大多是无状态的: 模型接收一个输入(例如一张图片),独立地计算并返回一个输出(例如分类标签或边界框坐标)。服务器不需要为同一个用户或会话的连续请求保留任何中间状态。
- 输入和输出的数据大小相对固定和可预测: 例如,图像分类模型的输入通常是固定尺寸的图片,输出是固定长度的类别概率向量。
- 计算模式相对单一且批处理简单: 对于同一模型,不同请求的计算路径和资源消耗通常比较相似,因此可以将它们简单地堆叠起来形成批次进行处理,以摊薄模型加载和计算启动的开销。
那么,当这些为“传统DNN”设计的服务框架遭遇LLM时,又会暴露出哪些局限性呢?这正是你的论文中着重指出的地方。
- 对自回归生成特性的支持不足: LLM的核心是逐词元迭代生成。传统的DNN服务框架通常是为“一次性”计算(一个输入,一个完整的输出)设计的,它们可能缺乏对这种长序列、多步骤、持续交互式的生成过程进行有效管理和优化的机制。
- KV缓存管理机制的缺失或简陋:这是最致命的短板。 正如我们反复强调的,KV缓存是LLM推理的灵魂,但它也是一个巨大的“麻烦制造者”——体积庞大、动态增长、对性能至关重要。传统的DNN模型通常不需要(或者只需要非常小的)类似KV缓存这样的、需要在请求处理过程中持续维护和高速访问的巨大中间状态。因此,这些框架缺乏专门为高效管理KV缓存而设计的复杂机制,例如我们后续会学到的像vLLM中的PagedAttention那样的精细化内存管理技术,或者高效的KV缓存压缩、共享、迁移策略等。你的论文中提到,传统的深度学习模型(DNN)调度策略难以直接适用于LLM服务,一个核心原因就是LLM服务请求在特性上的高度异构性以及执行的不可预测性,这些都与KV缓存的动态行为密切相关 [cite: 18]。
- 缺乏高级的批处理策略 (如连续批处理/迭代级批处理): 对于传统的DNN模型,简单的静态批处理(即等待一个批次积累到足够数量的请求,或者等待一个超时时间到达,然后再统一开始处理)可能还能工作。但对于LLM,这种方式效率极低。因为不同LLM请求的输入长度、期望输出长度以及实际生成时间差异巨大。如果采用静态批处理,GPU可能会因为等待批次中最慢的那个请求完成而长时间空闲,或者因为凑不齐一个足够大的批次而导致利用率低下。LLM服务迫切需要更灵活、更动态的批处理策略。例如,后续我们会接触到的“连续批处理 (Continuous Batching)”允许在批次正在GPU上执行的过程中,动态地将新到达的、已完成预填充的请求加入到当前批次中,或者将批次中已经完成生成的请求及时移出,从而最大限度地提升GPU的并发处理能力和利用率。像Orca系统就提出了“迭代级调度 (iteration-level scheduling)”或称为选择性批处理,它允许更灵活地组合和执行不同请求的计算迭代,也是对传统静态批处理的重要改进 [cite: 18, 57]。
- 对预填充和解码阶段异构性的处理不佳: 我们在第一部分提到,LLM推理的预填充阶段(处理输入prompt,计算密集型,可并行度高)和解码阶段(逐词元生成,通常是内存带宽受限,迭代特性限制并行度)具有显著不同的计算和资源访问特征。传统的DNN服务系统通常不会对这两个阶段进行区分对待和专门优化。而现代的、为LLM设计的服务系统,比如DistServe,则会明确地将这两个阶段解耦 (decouple),甚至可以将它们调度到不同的GPU硬件组上,针对各自的特性进行独立的资源分配和并行策略优化,以实现整体性能的最大化 [cite: 30, 58]。
- 难以应对LLM请求的高度异构性和执行的不可预测性: 这是你的论文中反复强调的核心挑战之一。LLM服务请求在输入长度(prompt长度)、期望输出长度、计算资源需求(尤其是KV缓存需求)、以及用户对延迟的敏感度等方面,都表现出极高程度的异构性 (Heterogeneity) [cite: 18]。更棘手的是,单个请求的实际执行时间(特别是最终会生成多少个token)在请求到达时往往是不可预测的 (Unpredictability) [cite: 18]。传统的DNN调度方法通常建立在请求具有更强的同质性和行为可预测性的假设之上,因此它们在面对LLM服务这种“千人千面”、行为多变的请求负载时,往往会显得捉襟见肘,难以做出最优的调度决策,容易导致请求长时间排队、尾延迟过高、或者GPU资源利用率低下等问题 [cite: 18]。
3.3 结论:LLM服务呼唤专门化的解决方案 🌟
通过上面的对比分析,我们可以清晰地看到:无论是传统的通用Web服务架构,还是为早期其他类型DNN模型设计的服务框架,都难以有效应对LLM推理服务所带来的独特挑战。
因此,LLM服务迫切需要专门化、定制化的解决方案。这些专门化的LLM服务系统,其核心竞争力就在于它们能够深刻理解并针对性地优化LLM推理的每一个环节和特性。后续课程中我们将要学习的大量高级技术,都属于这个“专门化”的范畴,例如:
- 通过像PagedAttention这样的技术来高效、灵活地管理和优化巨大的、动态的KV缓存。
- 实现如连续批处理 (Continuous Batching)、选择性批处理 (Selective Batching) 或迭代级调度 (Iteration-level Scheduling) 等高级批处理策略,以最大限度地提升GPU的并发度和吞吐量。
- 对预填充 (Prefill) 和解码 (Decode) 阶段进行解耦和协同优化。
- 设计和实现高效的KV缓存迁移机制,为更灵活的负载均衡和请求重调度提供支持。
- 以及我们整个课程的重中之重——研发和应用复杂且智能的动态调度机制 (Dynamic Scheduling),使其能够实时感知系统状态和请求特性,动态调整资源分配和执行顺序,从而在多变的环境下实现性能、成本和QoS的最佳平衡。
这些专门化的技术和系统设计,正是当前学术界和工业界在LLM服务领域努力攻关的热点方向。
总结与展望
同学们,今天我们通过对比分析,明确了为什么LLM服务需要专门的系统架构和技术支持。我们看到,无论是传统的Web服务还是早期的DNN模型服务框架,在面对LLM独特的自回归生成方式、庞大且动态的KV缓存、以及请求的高度异构性和不可预测性时,都显得力不从心。
这为我们接下来的学习奠定了基础:正因为存在这些“不适应”,才催生了对LLM服务进行深度优化的需求。在下周,我们将正式进入这些“核心挑战”的细节,逐一剖析你的论文第二章中详细阐述的各个难点。只有深刻理解了“痛点”在哪里,我们才能更好地理解和评价后续的各种“药方”(即动态调度等关键技术)是如何对症下药的。
希望大家课后能仔细回味这部分内容,思考一下,如果让你从头设计一个LLM服务系统,基于今天学到的这些“局限性”,你会优先考虑解决哪些问题?
好,今天的内容就到这里。谢谢大家!
第三周大纲
好的,我们来看第三周的课程大纲。
根据我们之前的计划,第三周的主题是:“LLM服务的性能指标与初步挑战”。这一周的目标是让同学们理解衡量LLM服务性能的关键指标,并开始接触LLM服务面临的初步的、宏观层面的挑战,为后续更深入地探讨具体的核心挑战和动态调度技术做铺垫。
第三周:LLM服务的性能指标与初步挑战
核心目标:
- 掌握衡量LLM服务性能和质量的关键指标。
- 理解服务等级目标 (SLO) 的概念及其在LLM服务中的重要性。
- 初步认识LLM服务在宏观层面面临的挑战,如高计算复杂度和大内存占用。
- 回顾传统调度策略及其在LLM服务场景下的初步不适应性。
第一部分:LLM服务的关键性能指标 (Key Performance Indicators - KPIs) (建议时长:50-60分钟)
- 1.1 延迟 (Latency) ⏱️
- 首个词元生成时间 (Time To First Token - TTFT):
- 定义:从用户发送请求到接收到第一个输出词元所需的时间 [cite: 20]。
- 重要性:对于交互式应用(如聊天机器人、实时代码助手)至关重要,直接影响用户感知到的系统响应速度和流畅性 [cite: 20]。
- 影响因素:主要受输入提示(prompt)的处理(即预填充阶段)效率、网络延迟、调度排队时间等影响。
- 词元间延迟 (Inter-Token Latency / Time Per Output Token - TPOT/TPTL):
- 定义:生成后续每个词元平均所需的时间。
- 重要性:影响用户阅读生成内容时的流畅体验,以及长文本生成的总时长。
- 影响因素:主要受模型本身的解码速度、KV缓存的读写效率、GPU计算能力等影响。
- 端到端延迟 (End-to-End Latency):
- 定义:从用户发送请求到接收到完整响应(最后一个词元或结束标记)的总时间。
- 重要性:衡量整个服务请求的总体耗时。
- 首个词元生成时间 (Time To First Token - TTFT):
- 1.2 吞吐量 (Throughput) 🚀
- 请求吞吐量 (Requests Per Second - RPS):
- 定义:系统在单位时间内能够成功处理的用户请求数量。
- 词元吞吐量 (Tokens Per Second - TPS):
- 定义:系统在单位时间内能够生成的总词元数量(包括输入和输出)。这是衡量LLM服务计算效率的更直接指标。
- 影响因素:GPU并行处理能力、批处理大小和效率、内存带宽、调度算法等。
- 请求吞吐量 (Requests Per Second - RPS):
- 1.3 并发用户数/请求数 (Concurrency) 👥
- 定义:系统能够同时处理的活跃用户请求数量,同时保持可接受的性能水平。
- 重要性:衡量系统的容量和可扩展性。
- 1.4 成本 (Cost) 💰
- 单位请求成本 / 单位词元成本:
- 定义:处理每个请求或生成每个词元所需的硬件资源(GPU、CPU、内存、带宽)和能源消耗的成本。
- 总拥有成本 (Total Cost of Ownership - TCO): 包括硬件采购、电力、运维等。
- 重要性:直接关系到LLM服务的商业可行性和经济效益。
- 单位请求成本 / 单位词元成本:
- 1.5 其他指标
- GPU利用率 (GPU Utilization): 包括计算单元利用率、显存利用率、显存带宽利用率等。高利用率通常意味着资源得到了有效利用。
- 服务可用性 (Availability): 系统正常运行并能提供服务的时间百分比。
第二部分:服务等级目标 (Service Level Objectives - SLOs) (建议时长:30-40分钟)
- 2.1 什么是SLO?
- 定义:服务提供商对其向用户提供的服务在特定性能指标上所做的量化承诺。它是衡量服务质量 (Quality of Service - QoS) 的具体标准。
- 与SLA (Service Level Agreement) 和SLI (Service Level Indicator) 的关系:SLI是实际测量的性能指标(如P99延迟),SLO是基于SLI设定的目标(如P99延迟 < 500ms),SLA是包含SLO的正式协议,通常包含未达标时的补偿条款。
- 2.2 LLM服务中典型的SLO示例
- 例如:P99 TTFT < 200ms;平均词元间延迟 < 50ms;请求成功率 > 99.9%;系统在90%的时间内词元吞吐量 > 1000 TPS。
- 不同应用场景或付费用户可能对应不同的SLO。你的论文中提到,商业化的LLM服务中,不同的应用场景或付费用户往往对应着不同的服务等级目标 (SLO) [cite: 21]。例如,提供付费增值服务的ChatGPT Plus就承诺为其用户提供更快的响应速度 [cite: 21]。
- 2.3 SLO的重要性
- 指导系统设计和优化方向。
- 设定用户期望,提升用户满意度。
- 作为衡量服务性能和可靠性的基准。
- 2.4 在LLM服务中保障SLO的挑战
- 负载的异构性和执行的不可预测性使得准确预测请求完成时间变得困难,从而对SLO的达成构成威胁 [cite: 20, 22]。
- 多租户环境下,不同请求间的性能干扰可能导致SLO违规 [cite: 21]。论文指出,在多租户共享GPU资源的环境下,实现严格的SLO保障和性能隔离极具挑战性 [cite: 21]。
第三部分:LLM服务面临的初步挑战 (宏观层面) (建议时长:40-50分钟)
在详细剖析各项核心挑战之前,我们先从宏观层面认识一下LLM服务天然面临的一些初步的、全局性的挑战。这些挑战源于LLM模型本身的特性。
- 3.1 高计算复杂度 (High Computational Complexity) 🤯
- LLM通常包含数十亿甚至数万亿的参数,导致推理过程计算密集 [cite: 18]。
- 自回归生成方式,即逐个token生成输出,且每个新token的生成依赖于之前所有已生成的token,使得单个请求需要多次迭代计算 [cite: 18]。
- 即使是单个词元的生成,也涉及到大量的矩阵运算和注意力计算。
- Implication: 需要强大的计算硬件(主要是GPU/TPU),并且对计算效率的优化至关重要。
- 3.2 大内存占用 (Large Memory Footprint) 💾
- 模型参数存储: 巨大的参数量本身就需要大量的存储空间(通常是GPU显存)。
- KV缓存: 正如我们反复强调的,为了避免重复计算,推理引擎需要缓存大量的中间状态,即键值缓存 (KV Cache) [cite: 18]。KV Cache的体积庞大且随生成长度动态变化,对GPU显存造成极大压力 [cite: 18]。它往往比模型参数本身占用更多的显存。
- 其他激活值和临时数据: 推理过程中还会产生其他的中间计算结果,也需要占用显存。
- Implication: GPU显存容量和带宽成为关键瓶颈。对显存的高效管理、压缩、共享等技术至关重要。
- 3.3 传统调度策略的初步不适应性 🚧
- 回顾一些经典的、简单的调度策略:
- 先来先服务 (First-Come, First-Served - FCFS): 按请求到达顺序处理。
- 轮询 (Round Robin): 将请求依次分配给可用的工作单元。
- 最短作业优先 (Shortest Job First - SJF) / 最短剩余时间优先 (Shortest Remaining Time First - SRTF): 优先处理预计执行时间最短的作业。
- 初步分析其在LLM服务场景下的问题:
- FCFS的队头阻塞 (Head-of-Line Blocking): 一个耗时较长的请求(例如,长prompt或需要生成很长输出的请求)会阻塞其后大量耗时较短的请求,从而显著拉高平均延迟和尾延迟 [cite: 20]。
- SJF/SRTF的挑战: LLM请求的实际执行时间(尤其是输出token数量)在请求到达时往往是不可预测的 [cite: 18],这使得准确应用SJF/SRTF变得非常困难。SSJF等工作尝试用代理模型预测输出长度来实现近似SJF [cite: 32, 47]。
- 简单轮询的不足: 未考虑请求的异构性、优先级、SLO需求,也未考虑工作单元的当前具体负载(如KV缓存占用情况),难以实现高效的资源利用和性能保障。
- 论文指出,传统的深度学习模型(DNN)调度策略,如简单的轮询分发或基于固定批处理大小的静态调度,难以直接适用于LLM服务 [cite: 18]。这主要是因为LLM服务请求在特性上表现出高度的异构性,并且单个请求的实际执行时间往往是不可预测的 [cite: 18]。
- 回顾一些经典的、简单的调度策略:
总结与展望 (建议时长:5-10分钟)
- 回顾: 本周我们学习了衡量LLM服务性能的关键指标,理解了SLO的重要性,并从宏观层面初步认识了LLM服务因其高计算复杂度和大内存占用而带来的挑战。我们还看到,一些传统的、简单的调度策略在面对LLM的特性时显得力不从心。
- 展望: 这些初步的挑战只是冰山一角。在下一周(第四周),我们将正式进入你的论文第二章所详细阐述的“大语言模型服务动态调度的核心挑战”,更深入地剖析负载的异构性与执行的不可预测性、SLO保障与性能隔离难题、GPU资源碎片化与高效利用,以及请求优先级与差异化服务需求等更为具体和棘手的问题。理解了这些核心挑战,我们才能真正体会到动态调度机制的价值所在。
第三部分
好的,同学们,我们继续第三周的课程。
在前面两个部分,我们已经详细了解了衡量LLM服务性能与质量的关键指标,以及服务等级目标(SLO)在其中的重要性。现在,我们要开始触及“硬骨头”了——LLM服务在宏观层面,由于其模型本身的特性,就天然面临着的一些初步的、全局性的挑战。
理解这些宏观挑战至关重要,因为它们是后续所有更细致、更具体的“核心挑战”的根源,也是我们为什么需要专门研究LLM动态调度等高级技术的根本原因。这些挑战之所以称为“宏观”,是因为它们是基础性的,任何一个LLM服务系统都必须首先直面它们。
第三部分:LLM服务面临的初步挑战 (宏观层面)
3.1 高计算复杂度 (High Computational Complexity) 🤯
第一个扑面而来的挑战,就是LLM惊人的计算复杂度。
- 3.1.1 参数规模的直接影响 (Direct Impact of Parameter Scale):
- 大家可能经常听到“百亿模型”、“千亿模型”甚至“万亿模型”这样的说法。这里的“参数”,指的就是构成神经网络的权重(weights)和偏置(biases)。它们是模型从海量数据中学习到的“知识”的载体。
- LLM的参数规模是巨大的。正如你的论文中提到,LLM通常包含数十亿甚至数万亿的参数 [cite: 18]。可以想象,参数越多,模型理论上能编码的信息就越复杂,表达能力就越强。
- 但是,每一个参数在模型进行推理(即生成文本)时,都可能参与到计算中,主要是大量的矩阵乘法运算。简单来说,参数越多,每生成一个词元(token)所需要的计算量(通常用FLOPs,即浮点运算次数来衡量)就越大。这是一个非常直接的对应关系。
- 从理论层面看,模型的参数量与其表达潜力和学习能力密切相关,但这种潜力是以推理时实实在在的计算开销为代价的。
- 3.1.2 自回归生成的迭代本质 (Iterative Nature of Autoregressive Generation):
- 我们在第一、二周反复强调过,LLM是逐个词元生成的,并且每一步的生成都依赖于之前所有已生成的词元 [cite: 18]。
- 你的论文明确指出,“LLM的自回归(Autoregressive)生成方式,即逐个token(词元)生成输出,且每个新token的生成依赖于之前所有已生成的token,使得单个请求需要多次迭代计算” [cite: 18]。这意味着,如果模型需要生成N个词元的回复,那么整个模型(或者至少是模型中与生成相关的关键部分)就需要完整地计算N次。
- 这与很多非自回归的模型(比如一次性输出分类结果的图像识别模型)形成了鲜明对比。后者的主要计算过程通常在接收到输入后执行一次即可。而LLM的这种迭代计算特性,极大地放大了其本已很高的单次计算成本。
- 3.1.3 单个词元生成的计算细节 (Computational Details of Single Token Generation):
- 即使我们只看生成一个词元的过程,其内部也涉及到非常密集的计算。回想一下Transformer的结构:
- 自注意力层 (Self-Attention): 需要计算Query、Key、Value向量,然后是Query和Key的点积得到注意力分数矩阵,再与Value向量进行加权求和。这些步骤都涉及到大规模的矩阵乘法。
- 前馈网络层 (Feed-Forward Networks - FFNs): 通常包含两个线性变换(又是矩阵乘法)和一个激活函数。
- 并且,这些复杂的计算模块(自注意力+FFN)会在模型中堆叠很多层(比如几十层甚至上百层)。所以,即便只是为了预测出下一个小小的词元,数据也要在这些庞大的计算单元中“长途跋涉”一番。
- 即使我们只看生成一个词元的过程,其内部也涉及到非常密集的计算。回想一下Transformer的结构:
- 3.1.4 对硬件和优化的需求 (Implications for Hardware and Optimization):
- 这种极高的计算复杂度,首先就对硬件提出了严苛的要求。目前来看,只有像GPU、TPU这样具有大规模并行处理能力的硬件,才能在可接受的时间内完成LLM的推理计算。在CPU上对大型LLM进行交互式推理几乎是不现实的,速度会非常缓慢。
- 同时也催生了对各种计算优化技术的研究。虽然这些不是本课程的重点,但大家需要知道,学术界和工业界在模型层面做了很多努力,例如:
- 更高效的模型架构探索: 寻找计算量更小但性能依然强大的模型结构。
- 模型量化 (Quantization): 将模型参数从高精度(如32位浮点数)转换为低精度(如16位、8位甚至更低),以减少计算量和内存占用,但可能会牺牲一些模型精度。
- 模型剪枝 (Pruning): 识别并移除模型中相对不那么重要的参数或连接,以达到压缩模型、减少计算的目的。
- 优化计算库 (Optimized Kernels): 开发针对特定硬件(如各种型号GPU)高度优化的线性代数运算库。
3.2 大内存占用 (Large Memory Footprint) 💾
与高计算复杂度相伴相生的,是LLM同样惊人的内存占用。这里的内存,主要指的是高速但昂贵的GPU显存。
- 3.2.1 模型参数的存储需求 (Storage Needs for Model Parameters):
- 模型的参数本身就需要巨大的存储空间。我们举个例子:一个拥有1750亿(175B)参数的模型(比如GPT-3的一个版本),如果每个参数用16位浮点数(即半精度,2个字节)来存储,那么仅仅是模型权重就需要 $175 \times 10^9 \times 2 \text{ bytes} = 350 \text{ GB}$ 的存储空间 [cite: 18]。
- 这个数字远远超过了目前单块消费级甚至专业级GPU的显存容量(通常是几十GB到近百GB)。这就意味着,即使只是为了“装下”模型本身,也可能需要采用复杂的模型并行技术,即将一个模型的不同部分分散到多个GPU上协同工作才能完成一次推理。或者,采用“卸载”(offloading)技术,在推理时动态地将模型不常用的部分暂时放到CPU内存中,需要时再调回GPU显存,但这会带来额外的延迟。
- 3.2.2 KV缓存的统治地位 (The Dominance of KV Cache):
- 这是内存占用的另一个“大头”,而且往往比模型参数本身更“喧宾夺主”。我们反复强调,为了避免在自回归生成时重复计算历史信息的注意力状态,系统需要缓存每个词元在每个注意力层计算得到的Key和Value向量,这就是KV缓存 [cite: 18]。
- 你的论文准确地指出了,“KV Cache 的体积庞大且随生成长度动态变化,对GPU显存造成极大压力” [cite: 18]。
- KV缓存的大小是如何计算的呢?粗略来说,它约等于:(模型层数) $\times$ (批次中序列的数量) $\times$ (每个序列的当前长度) $\times$ (每个注意力头的隐藏维度) $\times$ (注意力头的数量) $\times$ (每个数据元素占用的字节数)。可以看到,序列越长、批次越大、模型越深越宽,KV缓存就越大。对于需要处理长上下文(比如数万甚至数十万词元的文档)的应用,或者在高并发、大批次服务的场景下,KV缓存的体积可以轻易达到数十乃至上百GB。
- 更麻烦的是它的动态性:每生成一个新的词元,KV缓存就会相应地增长一点。这使得精确的显存预估和分配变得非常困难。
- 3.2.3 其他激活值与临时数据 (Other Activations and Temporary Data):
- 除了模型参数和KV缓存这两大“内存消耗巨头”之外,在神经网络进行前向传播(即推理计算)的过程中,还会产生很多其他的中间计算结果,我们称之为“激活值”(activations)。这些激活值也需要临时存储在显存中,以便后续层的计算使用。
- 此外,GPU执行计算任务时,其底层的CUDA等编程接口也可能需要一些额外的“工作空间”(workspace)内存。
- 3.2.4 对硬件和优化的需求 (Implications for Hardware and Optimization):
- 硬件层面: 这就解释了为什么现代GPU都配备了高带宽内存 (High-Bandwidth Memory - HBM)。GPU的显存容量和显存带宽(即数据从显存读写到计算单元的速度)往往是制约LLM服务性能(尤其是处理长序列或大批次时)的关键瓶颈。
- 优化层面: 巨大的内存压力也催生了各种针对内存优化的研究:
- KV缓存压缩技术: 例如,通过量化KV缓存中的值,或者利用其稀疏性进行压缩。
- 更精细的KV缓存管理机制: 比如我们多次提到的vLLM中的PagedAttention技术 [cite: 24],它借鉴操作系统的虚拟内存分页思想,允许KV缓存以非连续的块形式存储在显存中,从而减少内存碎片,提高显存利用率。
- KV缓存卸载 (KV Cache Offloading): 在GPU显存极度紧张时,可以将一部分不那么活跃的请求的KV缓存暂时换出到CPU主内存,等需要时再换回。这是一种用时间(换入换出的延迟)换空间(GPU显存)的策略。
- 改变模型架构以减少KV缓存: 例如,多查询注意力 (Multi-Query Attention - MQA) 或分组查询注意力 (Grouped-Query Attention - GQA) 这样的Transformer架构变体,它们通过让多个查询头共享同一组Key和Value向量,从而显著减小KV缓存的大小,代价是可能略微影响模型性能。
3.3 传统调度策略的初步不适应性 🚧
面对LLM这种计算和内存都极其“贪婪”且行为独特的“怪兽”,我们沿用过去那些为相对简单、行为可预测的任务设计的传统调度策略,会发生什么呢?答案是:它们往往会“水土不服”。
- 3.3.1 回顾经典调度策略及其设计初衷 (Review of Classic Strategies and Their Design Rationale):
- 让我们先回忆几个经典的调度算法:
- 先来先服务 (First-Come, First-Served - FCFS): 这是最简单、最直观的策略。谁先到,谁就先被服务。它的设计初衷是保证公平性(按到达顺序),并且实现简单。它通常假设任务的特性要么比较同质,要么顺序本身就是最重要的考量。
- 轮询 (Round Robin): 为了避免某个任务长时间占用资源导致其他任务饿死,轮询策略会给每个等待的任务分配一个固定的时间片,轮流执行。它主要目标是提高系统的响应性和交互性,特别适用于有大量小型、计算需求相似的交互式任务的场景。
- 最短作业优先 (Shortest Job First - SJF) / 最短剩余时间优先 (Shortest Remaining Time First - SRTF): 这两种策略的核心思想都是优先处理那些预计执行时间最短的任务(SRTF是SJF的抢占式版本)。理论上,在所有任务同时到达的情况下,SJF能够最小化平均等待时间和平均周转时间。它们的设计初衷是为了优化整体的作业吞吐效率,常见于批处理系统中,前提是能够比较准确地预估每个任务的执行时长。
- 让我们先回忆几个经典的调度算法:
- 3.3.2 在LLM服务场景下的具体问题 (Specific Problems in LLM Serving Context):
- FCFS 与队头阻塞 (Head-of-Line - HoL Blocking):
- 想象一下这个场景:一个用户提交了一个需要生成一篇2000词元长篇报告的请求(这会是一个耗时很长的任务)。紧接着,又有10个用户分别提交了只需要模型回复一两句话的聊天请求(这些是耗时很短的任务)。如果采用FCFS,这10个用户的短请求就必须眼巴巴地排在那个长请求后面,等待它慢悠悠地完成。结果就是,这10个用户的体验会非常糟糕,他们会感觉到系统反应迟钝,即使他们自己的请求本身很简单。这就是典型的“队头阻塞”——一个耗时长的大任务阻塞了后面大量耗时短的小任务。
- 正如你的论文中明确指出的,在混合了长短请求的场景下,FCFS调度策略极易发生队头阻塞,从而显著拉高平均延迟和尾延迟 [cite: 18, 20]。这正是FCFS与LLM请求执行时间高度可变这一特性结合产生的恶果。
- SJF/SRTF 与不可预测性 (Unpredictability):
- SJF/SRTF策略听起来很美好,但它们有一个致命的前提:我们必须能够预先知道每个任务的执行时间。然而,对于LLM服务,你的论文指出,“单个请求的实际执行时间(尤其是输出token数量)在请求到达时往往是不可预测的” [cite: 18]。我们无法提前准确知道模型会为某个用户的prompt生成多少个词元的回复。
- 尽管有一些研究工作,比如SSJF [cite: 32],尝试使用一个轻量级的“代理模型”来预测LLM请求的输出序列长度,从而近似地实现SJF/SRTF,但这些预测并非总是百分之百准确,而且预测本身也会引入额外的开销和延迟。
- 如果我们错误地将一个实际耗时很长的请求预测为短请求并优先调度了它,或者反之,都会导致调度效果偏离预期,甚至可能比FCFS更差。
- 轮询 (Round Robin) 对LLM的低效性:
- 对于LLM这种重状态、重计算的任务,频繁的上下文切换(Context Switching)代价是非常高昂的。如果采用轮询,每当一个请求的时间片用完,系统就需要保存它当前的完整状态(主要是巨大的KV缓存),然后加载下一个请求的状态。这个保存和加载的过程本身就会消耗大量的时间和显存带宽。
- 此外,轮询策略通常不考虑请求之间的巨大差异性,例如它们的优先级、SLO需求、当前的KV缓存大小、以及它们对GPU特定计算单元或内存资源的偏好等。简单地给每个请求一个“时间片”,对于精细化管理和高效利用宝贵的GPU资源来说,是远远不够的。
- FCFS 与队头阻塞 (Head-of-Line - HoL Blocking):
- 3.3.3 论文的核心论点 (The Thesis’s Core Argument on This Topic):
- 你的论文非常精准地总结了这一点:“传统的深度学习模型(DNN)调度策略,如简单的轮询分发或基于固定批处理大小的静态调度,难以直接适用于LLM服务” [cite: 18]。
- 原因何在?论文紧接着给出了答案:“这主要是因为LLM服务请求在特性上表现出高度异构性,并且单个请求的实际执行时间往往是不可预测的” [cite: 18]。
- 这个结论,为我们后续课程为什么要深入研究那些更复杂、更智能的动态调度和LLM感知的调度策略,埋下了坚实的伏笔。
结论/过渡 (2-3分钟):
同学们,通过今天的详细讲解,我们应该对LLM服务在宏观层面面临的这三大初步挑战——高计算复杂度、大内存占用、以及传统调度策略的初步不适应性——有了更深刻的体会。
大家要认识到,这些挑战并非孤立存在,它们之间是相互作用、相互放大的。例如,巨大的内存占用(特别是KV缓存)会加剧由于执行时间不可预测而导致的调度困难,因为如果内存管理不当,很容易产生碎片,使得即使有空闲计算资源也无法接纳新的请求。
正是这些基础性的、源于LLM模型本身特性的宏观挑战,催生了整个LLM服务系统研究领域,并驱使着学术界和工业界不断探索更优化的模型、更高效的硬件、以及更智能的软件系统(尤其是调度系统)。
在下一周,我们将更进一步,深入到你的论文第二章所阐述的“大语言模型服务动态调度的核心挑战”,去审视那些更为具体、更为细致、也更为棘手的难题。只有真正理解了这些挑战的“痛”,我们才能更好地体会后续各种动态调度技术是如何“疗伤”的。
今天的课就到这里,谢谢大家!
第四周大纲
好的,同学们,我们进入第四周的学习。
在前三周,我们已经建立了对LLM、其推理过程、关键性能指标及初步挑战的认识。我们了解到LLM的计算和内存需求巨大,传统的服务和调度策略在它们面前显得力不从心。
从本周开始,我们将更加深入地剖析LLM服务动态调度所面临的核心挑战。这些挑战是设计高效LLM服务系统,特别是动态调度机制时,必须正面应对的关键问题。我们的主要参考资料,依然是白欣宇同学的这篇优秀论文。本周,我们将重点聚焦于论文第二章的第一节(2.1节)所阐述的内容 [cite: 20]:负载的异构性 (Load Heterogeneity) 与 执行的不可预测性 (Execution Unpredictability)。
第四周:核心挑战 (一): LLM服务中的负载异构性与执行不可预测性
第一部分:核心挑战绪论 (回顾与导引) (建议时长:10-15分钟)
- 首先,我们简单回顾一下上周提到的“初步挑战”:LLM具有高计算复杂度和大内存占用的固有特性,使得传统调度策略难以直接适用 [cite: 18]。
- 现在,我们要从这些宏观认知更进一步,去审视那些更为具体、更为细致、对调度系统设计影响更为直接的核心挑战。这些挑战层层递进,共同构成了LLM服务优化的复杂图景。
- 未来几周,我们将以论文的第二章 “大语言模型服务动态调度的核心挑战” 为主要线索。本周我们首先攻克2.1节——负载异构性与执行不可预测性 [cite: 20]。这两个特性,可以说是描述LLM服务工作负载时最根本、最显著的特征。
第二部分:负载的异构性 (Load Heterogeneity) (建议时长:50-60分钟)
“异构性”这个词听起来可能有些学术,但它的意思很简单,就是“多样性”或“不一致性”。在LLM服务中,负载的异构性指的是系统接收到的用户请求在各种特征上表现出巨大的差异。
- 2.1 如何理解LLM服务中的负载异构性?
- LLM通常被设计为通用的模型,能够处理来自不同领域、具有不同意图的查询 [cite: 20]。正如论文中提到的,这种通用性和应用多样性直接导致了推理请求在特性上的巨大差异 [cite: 20]。
- 想象一下,一个LLM服务系统可能同时在为一个用户写一首短诗,为另一个用户总结一篇长篇科研论文,同时还在辅助一位程序员编写代码。这些任务的需求显然是截然不同的。
- 2.2 负载异构性的主要维度 (Dimensions of Heterogeneity):
- 输入长度 (Input Length / Prompt Length):
- 这是最直观的异构性来源。一个简单的问答请求可能只有几十个词元的输入,而一篇长文档的摘要任务则可能涉及数千甚至数万词元的输入 [cite: 20]。
- 输入长度直接影响预填充 (prefill) 阶段的计算量和初始KV缓存的分配大小。长prompt的预填充计算量大,需要的初始显存也多。
- 期望输出长度 (Expected/Actual Output Length):
- 用户期望模型生成的文本长度也是高度可变的。一个简单的“是/否”回答可能只需要一个词元,而生成一个故事或报告则可能需要数千词元。
- 更关键的是,如论文第一章和2.1节所强调的,单个请求的实际输出长度在请求到达时往往是不可预测的 [cite: 18, 20]。
- 输出长度直接决定了请求的总处理时间、最终KV缓存的大小,以及因此消耗的总计算和内存资源。
- 延迟敏感度 (Latency Sensitivity):
- 不同应用对延迟的容忍度千差万别。论文中提到,交互式聊天机器人通常对首个词元的生成时间(Time To First Token, TTFT)要求极为苛刻,以保证用户交互的流畅性 [cite: 20];而离线的批量翻译任务则可能更关注整体的吞吐量和总处理时间,对单个请求的延迟不那么敏感 [cite: 20]。
- 这种延迟敏感度的差异,意味着系统需要为不同类型的请求或用户提供差异化的服务等级目标 (SLO)。
- 计算资源需求 (Computational Resource Needs):
- 这与请求的输入输出长度、以及模型本身的复杂度紧密相关。长请求、复杂请求自然需要更多的计算资源。
- 我们还知道,LLM推理的预填充和解码阶段具有不同的计算特征:预填充通常是计算密集型 (compute-bound),而解码阶段(尤其是对于长序列)可能更多地受限于内存带宽 (memory-bandwidth-bound)。这种阶段性的资源需求差异也增加了异构性。
- 模型类型/版本 (Model Type/Version - 如果服务支持多种模型):
- 虽然我们的核心论文主要讨论的是单个大模型的服务,但在实际场景中,一个服务平台可能需要同时支持多个不同大小、不同功能或不同版本的LLM。这些不同的模型本身就具有不同的参数量、计算特性和内存占用,从而进一步加剧了负载的异构性。
- 输入长度 (Input Length / Prompt Length):
- 2.3 异构性对系统设计和性能的深远影响:
- 批处理 (Batching) 变得极其困难: 批处理是将多个请求打包在一起,利用GPU的并行计算能力同时处理,以提高吞吐量和硬件利用率。但如果一个批次中的请求特性差异巨大——有的输入很长,有的输出很长,有的计算量小,有的计算量大——就很难形成一个“优化的”批次。例如,一个长prompt的请求可能会显著拉长整个批次的预填充时间,而一个期望输出很长的请求则会使得该批次的KV缓存管理变得复杂且占用大量显存。静态的、固定大小的批处理策略在这种异构负载面前会非常低效。
- 资源分配与供应面临挑战: 如果系统接收到的请求类型和资源需求组合是不断变化的、多种多样的,那么如何合理地配置和供应计算资源(如GPU数量、显存大小)就成了一个难题。是按照峰值需求配置(可能导致平时资源浪费),还是按平均需求配置(可能导致高峰期性能下降)?
- 调度决策的复杂性急剧增加: 一个“聪明”的调度器必须能够感知到这种异构性,并根据不同请求的特性(如预估长度、延迟要求、优先级等)做出差异化的、自适应的调度决策。简单的调度策略(如我们上周讨论的FCFS或轮询)在这种高度异构的环境下,几乎不可能取得良好的整体性能。
- 这一切都指向一个明确的结论:面对负载异构性,我们需要动态的、自适应的、能够感知请求特征的调度机制。
第三部分:执行的不可预测性 (Execution Unpredictability) (建议时长:50-60分钟)
与负载异构性如影随形的另一个巨大挑战,是LLM请求执行过程中的“不可预测性”。
- 3.1 如何理解执行的不可预测性?
- 论文的摘要和2.1节都明确将“执行的不可预测性” (execution unpredictability) 列为核心挑战之一 [cite: 3, 20]。
- 它主要指的是,在请求到达系统时,我们无法预先准确知道这个请求需要执行多长时间才能完成,或者在其整个生命周期中究竟会消耗多少计算和内存资源。
- 3.2 根本原因:自回归生成与输出长度的不确定性:
- LLM的自回归生成机制是这一不可预测性的主要“元凶”。我们知道,模型是逐个词元生成输出,直到遇到一个特殊的“序列结束” (End-of-Sequence, EOS) 标记,或者达到了预设的最大生成长度限制才会停止 [cite: 20]。
- 关键在于,正如论文2.1节所强调的:“这意味着在请求开始执行前,系统无法预知最终会生成多少个token” [cite: 20]。模型会根据输入prompt的语义以及它自身的“理解”和“创造力”来决定何时结束生成。对于同一个prompt,模型在不同时候(如果解码策略带有随机性)或者对于微小的prompt变化,都可能生成不同长度的回复。
- 这个输出长度的不确定性,是导致请求总执行时间不可预测的最直接因素。
- 3.3 KV缓存的动态性进一步加剧不可预测性:
- 我们已经知道,KV缓存的大小与已生成的序列长度正相关 [cite: 20]。
- 既然输出序列的最终长度是不可预测的,那么每个请求最终会占用多大的KV缓存空间,以及它在生成过程中KV缓存的增长轨迹,也同样是不可预测的。
- 这对GPU的内存管理造成了极大的困扰。系统很难为一个新来的请求精确预留KV缓存空间。如果预留少了,生成过程中可能因显存不足(Out-of-Memory, OOM)而失败;如果预留多了,又会造成宝贵显存资源的浪费。
- 论文中一针见血地指出:“这种执行时间和资源需求的不可预测性,使得传统的基于先验知识的静态调度策略(如固定批大小、固定资源分配)难以奏效” [cite: 20]。
- 3.4 不可预测性对系统性能和调度的灾难性影响:
- 难以应用依赖预测的调度策略: 很多经典的、理论上性能很好的调度策略,如我们上周提到的最短作业优先 (Shortest Job First - SJF) 或最短剩余时间优先 (Shortest Remaining Time First - SRTF),它们有效性的前提是能够预先知道每个作业的执行时间。在LLM服务中,这个前提被打破了。如果我们不知道哪个请求是“短作业”,哪个是“长作业”,SJF/SRTF就无从谈起。
- 服务等级目标 (SLO) 保障更加困难: 如果连单个请求的完成时间都无法准确预测,那么要向用户保证一个严格的延迟SLO(比如P99延迟必须小于X毫秒)就变得异常困难。系统的行为充满了不确定性。
- 资源利用可能陷入两难:低效或过载:
- 如果系统为了安全起见,总是为每个请求都预留最坏情况下的资源(比如假设每个请求都会生成到最大长度),那么当大部分请求实际是短请求时,就会导致大量计算和内存资源被悲观地预留而得不到充分利用,系统整体效率低下。
- 反之,如果系统乐观地假设大部分请求都是短的,并基于此来分配资源和接纳新请求,那么一旦遇到一个或几个实际执行时间远超预期的长请求,就可能迅速耗尽资源,导致系统过载、新请求被拒绝,甚至正在运行的请求因KV缓存OOM而失败。
- 加剧请求排队与延迟抖动: 不可预测性使得系统的运行难以平稳。调度器很难做出最优的长期规划,可能导致请求在队列中不必要地等待,或者不同请求的延迟出现剧烈波动,用户体验下降。
第四部分:队头阻塞 (Head-of-Line Blocking) —— 异构性与不可预测性的直接恶果 (建议时长:20-30分钟)
当我们把负载的异构性(尤其是请求执行时间的巨大差异)和执行的不可预测性,与一些简单的调度策略(如FCFS)结合起来时,一个非常典型且严重的问题就会浮现出来,那就是“队头阻塞”。
- 4.1 什么是队头阻塞 (Head-of-Line - HoL Blocking)?
- 这是一个在各种排队系统中都可能出现的现象。简单来说,就是一个排在队列头部的、需要较长处理时间的任务,阻塞了其后所有任务(即使这些后续任务本身可能只需要很短的处理时间,并且系统也有空闲资源可以处理它们)被及时处理。
- 4.2 队头阻塞在LLM服务中的具体表现:
- 你的论文在2.1节明确指出了这个问题:“例如,广泛采用的先来先服务(FCFS)调度策略,在混合了长短请求的场景下,极易发生队头阻塞(Head-of-Line Blocking),即一个耗时较长的请求会阻塞其后大量耗时较短的请求,从而显著拉高平均延迟和尾延迟” [cite: 20]。该论文在此处引用了Qiu等人2024年的工作 [cite: 21](对应我们上下文中的源[89])来佐证这一观点。
- 我们可以用一个生动的例子来理解:假设在一个LLM服务窗口前,大家排队等候。第一个人要模型写一部长篇小说(比如输出1万词元),这可能需要GPU计算几分钟。紧随其后的10个人都只是想问一句天气或者让模型写一句诗(可能只需要输出几十个词元,几秒钟就能完成)。在FCFS策略下,这10个人必须等到那个“写小说”的请求完成之后才能轮到他们。即使旁边可能有空闲的GPU,或者这些短请求本可以很快得到满足,它们也只能无奈等待。
- 4.3 队头阻塞的严重影响:
- 平均延迟急剧增加: 那些本可以快速完成的短请求,因为被阻塞而经历了不必要的长时间等待,这会显著拉高所有请求的平均响应延迟。
- 尾延迟极其恶化 (P99, P99.9延迟飙升): 系统的“最差情况”延迟会变得非常糟糕。总有那么一部分不幸的短请求,因为排在了一个或多个长请求之后,其延迟会被放大数十倍甚至数百倍。这对那些对延迟非常敏感的交互式应用来说是灾难性的。
- 用户体验大幅下降: 提交简短、快速查询的用户,会因为系统中其他不相关的、耗时长的查询而受到严重影响,感到系统卡顿、反应迟缓。
- 服务等级目标 (SLO) 频繁违规: 特别是针对那些有严格延迟要求的短请求,它们的SLO很容易因为队头阻塞而无法得到保障。
- 4.4 队头阻塞与异构性、不可预测性的内在联系:
- 队头阻塞现象的发生和恶化,与我们本节课讨论的两个核心挑战紧密相关:
- 异构性是前提: 正是因为LLM请求的处理时间存在巨大差异(有的几秒,有的几分钟甚至更长),“长请求”阻塞“短请求”的现象才如此突出。如果所有请求的处理时间都差不多,队头阻塞的影响就不会那么严重。
- 不可预测性是助燃剂: 如果我们无法预知哪个请求会是“长请求”,就很难在它到达队列头部之前采取有效的措施来避免或缓解阻塞(比如,通过一个更智能的调度器将它暂时移到旁边,先处理短请求)。在简单的FCFS策略下,系统只能被动接受这种由于未知而造成的阻塞。
- 队头阻塞现象的发生和恶化,与我们本节课讨论的两个核心挑战紧密相关:
总结与展望 (建议时长:5-10分钟):
- 回顾: 同学们,今天我们深入剖析了LLM服务面临的两个最根本的负载特性挑战——负载的异构性和执行的不可预测性。我们看到,请求在输入输出长度、延迟敏感度、资源需求等多个维度上都存在巨大差异;同时,由于自回归生成和输出长度的不确定性,单个请求的执行过程也充满了未知。这些特性共同作用,使得像队头阻塞这样的性能问题在简单调度策略下极易发生。
- 强调: 大家务必认识到,这些不仅仅是小麻烦,它们是横亘在实现高性能、高效率、高服务质量的LLM服务面前的基础性障碍。它们直接挑战着传统服务架构和调度思想的有效性。
- 展望: 理解了工作负载本身的“刁钻”特性之后,我们下周将继续探讨由此引发的其他核心挑战。具体来说,我们将关注你的论文2.2节和2.3节的内容:在多租户共享资源的环境下,如何保障不同用户的服务等级目标(SLO)和性能隔离,以及如何应对宝贵的GPU资源(尤其是显存)的碎片化问题并实现高效利用。这些挑战同样严峻,并且与我们今天讨论的异构性和不可预测性密切相关。
希望大家课后能结合论文的2.1节,仔细消化今天的内容。思考一下,如果你是调度系统的设计者,面对这样“不听话”的请求负载,你会从哪些角度去寻求突破?
今天的课就到这里,谢谢大家!
第五周大纲
好的,同学们,我们进入课程的第五周。
在前几周,我们已经打下了坚实的基础:理解了LLM的推理特性、衡量其服务性能的指标,并初步探讨了LLM服务面临的宏观挑战,以及更为具体的负载异构性和执行不可预测性。我们看到,这些因素已经让LLM服务系统的设计和运行变得相当复杂。
本周,我们将聚焦于另一个核心挑战维度,这个挑战在多用户、多应用共享资源的商业化服务场景中尤为突出。我们将深入探讨论文第二章的2.2节——“服务等级目标(SLO)保障与性能隔离难题”。也就是说,当多个不同的“租户”(可以是不同的付费用户、不同的应用程序,或者同一应用的不同模块)同时使用我们的LLM服务系统时,我们如何确保每个租户都能获得其应有的服务质量?如何防止它们之间互相干扰?
第五周:核心挑战 (二): LLM服务中的服务等级目标(SLO)保障与性能隔离难题
第一部分:SLO回顾与挑战引入 (建议时长:10-15分钟)
- 首先,让我们快速回顾一下在第三周学习的服务等级目标 (SLO)。我们知道,SLO是服务提供商对其服务在特定性能指标上所做的量化承诺,例如P99延迟、吞吐量目标等。它是衡量服务质量 (QoS) 的关键。
- 在上一周,我们详细讨论了LLM负载的异构性和执行的不可预测性。大家可以想象,这些特性本身就已经使得稳定地达成某个SLO变得非常困难了——如果连单个请求的行为都难以预测,又如何保证整个服务在99%的情况下都能满足某个延迟目标呢?
- 本周,我们要在此基础上更进一步:即使我们能够一定程度上应对单个请求的“不确定性”,当系统需要同时服务多个用户或应用(即“多租户”环境),并且这些用户/应用可能有着不同的SLO需求时,新的、更为严峻的挑战就出现了。核心问题在于:如何在共享的、有限的资源上,为具有不同SLO的多个租户同时提供有保障的服务,并且防止它们之间的性能互相干扰? 这正是我们今天要深入探讨的主题,也直接对应于你的论文的2.2节。
第二部分:服务等级目标(SLO)保障的挑战 (建议时长:50-60分钟)
在商业化的LLM服务中,对SLO的保障是衡量服务成熟度和用户满意度的核心标准。然而,在实际运行中,尤其是在多租户共享GPU资源的环境下,要严格达成这些SLO承诺,却面临着重重困难。
- 2.1 商业化LLM服务与差异化服务质量 (QoS) 的背景
- 正如你的论文[cite: 21]中所指出的:“在商业化的LLM服务中,不同的应用场景或付费用户往往对应着不同的服务等级目标(SLO)”。例如,一个为企业内部关键业务提供支持的LLM应用,其对延迟和可靠性的要求,可能远高于一个仅供娱乐的聊天机器人。
- 论文[cite: 21]中也举了一个具体的例子:“提供付费增值服务的ChatGPT Plus 就承诺为其用户提供更快的响应速度”。这清晰地表明,服务提供商会根据用户的付费等级或服务类型,提供差异化的服务质量。
- 因此,LLM服务系统不仅要能够高效地处理请求,更关键的是要能够识别并满足这种差异化的QoS需求。它不能对所有请求一视同仁。
- 2.2 在多租户共享GPU环境中保障SLO为何如此困难?
- 核心原因:资源竞争 (Resource Competition)
- 论文[cite: 21]非常明确地指出:“LLM推理对GPU计算资源和显存带宽高度敏感”。GPU是LLM服务的核心动力,但也是昂贵且有限的。
- 当多个请求(可能来自不同的租户,具有不同的SLO)在同一个GPU实例上并发执行时,不可避免地会发生对这些有限资源的争夺。论文[cite: 21]继续写道:“当多个请求在同一GPU实例上并发执行时,它们会竞争这些有限的资源”。这些资源包括GPU的计算单元(SMs)、显存容量、以及至关重要的显存带宽(数据在显存和计算单元之间传输的速度)。
- 关键难题:性能干扰 (Performance Interference) —— “吵闹的邻居”问题
- 当多个租户共享同一物理GPU时,一个行为“恶劣”或资源需求极大的租户(我们常称之为“吵闹的邻居”)就可能对其他“邻居”的性能产生负面影响。
- 你的论文[cite: 21]对此有非常精辟的描述:“一个计算密集型或显存消耗巨大的请求,可能会对其他同批次或同实例上的请求产生显著的性能干扰,导致它们的执行延迟增加、吞吐量下降,甚至发生因显存不足而被抢占的情况”。想象一下,一个用户的请求可能正在进行一个非常耗费计算资源的预填充操作,或者它的KV缓存正在疯狂增长并大量消耗显存带宽,这都可能导致同一GPU上其他用户的请求“变慢”,即使那些请求本身可能很简单。
- 这种干扰的直接后果是什么呢?论文[cite: 22]总结道:“这种干扰使得单个请求的性能变得不稳定,难以准确预测其完成时间,从而对SLO的达成构成严重威胁”。如果单个请求的性能都变得像“过山车”一样不可预测,那么我们又如何能稳定地保证P99延迟这样的统计性SLO呢?
- 核心原因:资源竞争 (Resource Competition)
- 2.3 性能干扰对SLO的具体影响
- 延迟SLO难以保证: 对于那些支付了更高费用、期望获得低延迟服务的高优先级用户,如果他们的请求不幸与一个“资源大胃王”请求被调度到同一个GPU上,他们的延迟目标就很可能无法达成。
- 吞吐量SLO受影响: 某些租户可能签订了要求保证一定吞吐量的SLO。但如果其他租户的突发性高负载或低效请求占用了过多资源,就可能导致该租户的吞吐量目标无法实现。
- 系统整体可预测性下降: 性能干扰使得整个系统的行为变得更加难以预测和控制,这给服务运维和容量规划都带来了额外的复杂性。
- 2.4 与先前挑战的关联
- 我们上周讨论的负载异构性在这里会进一步加剧问题:不同的租户不仅请求特征不同,他们期望的SLO也可能天差地别。管理这种“双重异构性”对调度系统提出了更高的要求。
- 而执行的不可预测性则使得我们更难提前预知哪个请求可能会成为“吵闹的邻居”,从而也更难主动采取措施来规避或减轻其对他人的干扰。
第三部分:性能隔离难题 (The Performance Isolation Dilemma) (建议时长:50-60分钟)
为了应对上述因资源竞争和性能干扰导致的SLO保障难题,一个理想的解决方案是实现“性能隔离”。
- 3.1 什么是性能隔离 (Performance Isolation)?
- 性能隔离指的是,在一个多租户共享资源的环境中,系统应尽可能保证一个租户(或一个应用)的性能表现不受其他共享相同底层资源的租户(或应用)行为的影响。
- 目标是为每个租户提供一个仿佛“独享”的、性能可预测的执行环境,即使他们实际上是在共享物理硬件。
- 3.2 为什么性能隔离如此关键?
- SLO达成的基石: 没有有效的性能隔离,差异化的SLO就无从谈起。如果一个低优先级、行为不受约束的租户可以轻易地拖慢一个高优先级、对延迟极其敏感的租户,那么高优先级的SLO承诺就成了一句空话。
- 公平性与可预测性保障: 性能隔离有助于确保每个租户都能获得其“应得”的资源份额(可能根据付费等级或资源预留而有所不同),并体验到相对稳定和可预测的服务性能。这对于建立用户信任、进行准确计费都非常重要。
- 防止故障蔓延 (Cascading Failures): 在缺乏良好隔离的系统中,一个行为异常(例如,产生大量错误请求或无限循环生成)的租户可能会耗尽系统资源,导致整个服务集群过载,进而影响所有其他正常用户的服务,形成“雪崩效应”。良好的性能隔离可以将这种负面影响限制在始作俑者自身,保护其他租户。
- 3.3 在共享GPU上为LLM服务实现性能隔离的挑战何在?
- GPU资源的细粒度共享与隔离天生困难: GPU被设计为大规模并行处理器,其内部的计算单元(Streaming Multiprocessors - SMs)、内存控制器、L1/L2缓存等资源,在硬件层面上很多是全局共享的。要在如此细粒度的硬件资源上为不同的软件任务实现严格的性能隔离,本身就是一个非常具有挑战性的底层技术问题。我们很难像在CPU上那样,通过操作系统轻松地为不同进程分配独立的CPU核心和内存空间。
- KV缓存作为动态变化的共享核心状态: 我们知道KV缓存对LLM推理至关重要,但它也是动态增长且占用大量GPU显存的。当多个租户的请求在同一GPU上运行时,它们的KV缓存都需要在共享的显存中分配和管理。一个租户的巨大KV缓存不仅可能挤占其他租户所需的显存空间(导致OOM),还可能因频繁读写而大量消耗宝贵的显存带宽,从而间接影响其他租户的KV缓存访问速度和整体推理性能。如何有效地在共享显存中隔离和管理来自不同租户的、动态变化的KV缓存,是一个核心难题。
- 批处理 (Batching) 带来的两难: 为了提高GPU的整体利用率,服务系统通常希望将来自不同租户的请求合并到同一个批次中进行处理。这样做可以摊薄一些固定开销,让GPU的计算单元“忙起来”。但是,如果批处理做得不好,它也可能成为性能干扰的源头。例如,如果一个批次中混合了一个需要极长预填充时间的请求和几个对TTFT要求很高的短请求,那么这些短请求的TTFT就可能因为那个长预填充请求而被不必要地拉长。如何在提升利用率(通过批处理)和保障隔离性(避免批内干扰)之间取得平衡,是一个需要精巧设计的权衡。
- 隔离机制本身的开销与资源利用率的矛盾: 如果我们采取非常严格的隔离措施,例如,为每个租户或每个高优先级请求完全预留独立的GPU,或者采用非常粗粒度的时间分片(每个租户轮流使用GPU一个较长的时间段),虽然隔离效果可能很好,但很可能导致GPU资源在大部分时间未被充分利用(例如,当某个租户的负载较低时,其预留的GPU就空闲了)。因此,关键在于找到一种既能提供足够隔离度,又能维持较高资源利用率的机制。
- 3.4 解决思路与未来方向 (为后续课程埋下伏笔):
- 面对这些挑战,学术界和工业界正在积极探索各种解决方案。
- 你的论文[cite: 22]中就提到了两个代表性的系统思路:“Llumnix系统 Sun et al. (2024)的设计目标之一就是通过运行时跨实例重调度来增强请求间的隔离性”。这意味着,当系统检测到某个GPU实例上可能发生严重的性能干扰,或者某个高优先级请求的SLO可能受到威胁时,Llumnix可以动态地将其(或者干扰它的其他请求)迁移到其他更合适的GPU实例上,从而创造一个相对“干净”的执行环境。
- 论文[cite: 22, 23]中还提到:“而QLM系统 Agrawal et al. (2024) 则专注于SLO导向的队列管理和资源分配,以应对这一挑战”。这表明,通过设计能够理解并优先满足SLO的智能队列管理算法和资源分配策略,也是提升SLO保障能力和改善隔离性的重要途径。
- 这些例子都暗示我们,后续将要学习的动态调度、请求迁移、以及面向SLO的资源管理等技术,正是攻克性能隔离难题的关键武器。
总结与展望 (建议时长:5-10分钟):
- 回顾: 同学们,今天我们聚焦于LLM服务在多租户环境下面临的两个紧密相关的核心挑战:服务等级目标(SLO)的保障 和 性能隔离的实现。我们看到,由于GPU资源的共享特性以及LLM推理本身对这些资源的敏感性,当多个请求并发执行时,很容易发生资源竞争和性能干扰,从而使得严格保障每个租户的SLO变得异常困难,实现有效的性能隔离也极具挑战。
- 关联全局: 这些挑战,与我们上周学习的负载异构性和执行不可预测性相互交织,共同描绘出了一幅LLM服务系统设计与优化的复杂画卷。它们清晰地告诉我们,为什么我们需要超越传统的、简单的服务架构和调度方法,去寻求更加复杂、更加智能、更加针对LLM特性的解决方案。
- 展望: 在下周的课程中,我们将继续沿着论文第二章的思路,探讨另外两个同样棘手的核心挑战:由于KV缓存等因素导致的GPU资源(尤其是显存)的碎片化问题及其高效利用,以及在服务具有不同重要性的请求时,如何进行有效的请求优先级处理与差异化服务(对应论文2.3和2.4节)。这些内容将进一步加深我们对LLM服务复杂性的理解。
请大家课后再次回顾论文的2.2节,并思考一下,如果让你来设计一个多租户的LLM服务系统,你会如何权衡“尽可能地共享资源以提高利用率”和“尽可能地隔离租户以保障SLO”这两个看似矛盾的目标?
今天的课就到这里。谢谢大家!
第六周大纲
好的,同学们,我们来到第六周的课程。
在过去的几周里,我们已经层层深入,探讨了LLM服务面临的诸多挑战:从模型本身的计算和内存特性,到负载的异构性和执行的不可预测性,再到多租户环境下SLO保障和性能隔离的难题。这些挑战共同描绘了LLM服务系统设计的复杂性。
本周,我们将继续聚焦于论文第二章的后续内容,探讨另外两个同样关键的核心挑战:对应2.3节的“GPU资源碎片化与高效利用”,以及2.4节的“请求优先级与差异化服务需求”。这两个问题,一个关乎物理资源的有效利用,一个关乎服务策略的精细化管理,都是构建高性能、高满意度LLM服务不可回避的议题。
第六周:核心挑战 (三): GPU资源碎片化与高效利用,以及请求优先级与差异化服务
第一部分:回顾与资源管理挑战引入 (建议时长:10-15分钟)
- 首先,我们简要回顾一下上周的核心内容:在多租户共享GPU资源的环境下,由于资源竞争和性能干扰,要保障每个用户的SLO并实现有效的性能隔离是极其困难的。这背后,其实也反映了对宝贵GPU资源进行高效、公平分配和管理的挑战。
- 本周我们将延续这个“资源管理”的主线,但会从两个新的角度切入:
- 物理层面:即使我们有了调度策略,如果GPU最核心的资源——显存——本身就因为管理不当而大量浪费(碎片化),那么系统的整体容量和效率依然会大打折扣。
- 逻辑层面:当系统同时面对不同重要程度的请求时,如何确保那些“更重要”的请求得到应有的优先处理,以满足差异化的服务需求?
- 这两个问题,分别对应你的论文中的2.3节和2.4节,是我们今天要攻克的重点。
第二部分:GPU资源碎片化与高效利用 (建议时长:50-60分钟) - 对应论文2.3节
GPU,特别是其上的显存(VRAM),是LLM推理服务中最宝贵但也最容易成为瓶颈的资源之一 [cite: 22]。如何充分利用每一寸显存,避免浪费,是提升系统吞吐量和降低成本的关键。然而,一个幽灵般的问题常常困扰着我们,那就是“内存碎片化”。
- 2.1 GPU显存在LLM服务中的核心地位回顾
- 我们已经多次强调,LLM模型参数本身就需要巨大的显存空间。更为关键的是,动态增长且体积庞大的KV缓存,往往是显存消耗的“大头” [cite: 22]。
- 论文明确指出:“GPU 显存是 LLM 推理服务中最宝贵也最容易成为瓶颈的资源之一” [cite: 22]。
- 2.2 理解内存碎片化,特别是外部碎片 (External Fragmentation)
- 什么是外部碎片?想象一下你的GPU显存是一个大停车场。当车辆(代表内存分配请求,比如KV缓存)不断进进出出,并且每辆车大小不一时,停车场里可能会出现很多零散的、不连续的空车位。虽然把这些空车位加起来的总面积可能还很大,足够停下一辆大巴车(代表一个新的、需要大块连续内存的请求),但因为这些空车位都不够大且不连续,大巴车就是开不进去。这就是外部碎片。
- 你的论文对此有清晰的描述:“GPU显存极易产生外部碎片(External Fragmentation)。这意味着即使GPU总体上仍有空闲显存,这些空闲空间可能是不连续的小块,无法满足新到达的、尤其是需要较大初始KV缓存(如长prompt请求的预填充阶段)的请求对连续显存空间的需求” [cite: 22]。
- 2.3 LLM服务中产生显存碎片化的主要原因
- KV缓存的动态特性是主因: 这是碎片化最主要的“制造者”。不同请求的KV缓存不仅初始分配大小不同(取决于prompt长度),而且在生成过程中会动态增长,并在请求结束后被释放 [cite: 22]。这种频繁的、大小不一的分配和回收操作,就像在停车场里不断挪动不同大小的车,极易产生零散的空位。
- 输入输出长度的高度可变性: 我们在第四周讨论过负载的异构性,其中就包括输入prompt长度和期望输出长度的巨大差异 [cite: 22]。这意味着每次为新请求(尤其是在预填充阶段)分配KV缓存时,所需的内存块大小都是不确定的,这进一步加剧了内存的分割。
- 批处理与请求的动态加入/退出: 为了提高效率,请求会被动态地加入批次或从批次中移除。这个过程也伴随着KV缓存的分配和释放,是内存碎片产生的另一个重要场景。
- 2.4 显存碎片化带来的严重后果
- 有效GPU显存容量降低: 这是最直接的后果。虽然监控显示GPU可能还有20%的空闲显存,但由于这些空闲空间都是“碎片”,系统实际上可能无法再接纳任何需要稍大一些连续显存的新请求。看起来有,但用不上。
- 系统吞吐量下降: 如果因为碎片化导致无法为新请求分配内存,那么系统能够并发处理的请求数量就会减少,进而导致整体吞吐率的下降 [cite: 22]。
- 请求被拒绝或排队时间延长: 当新请求(尤其是那些需要较大初始KV缓存的,比如长prompt请求)因为找不到足够大的连续显存块而被拒绝,或者被迫长时间排队等待内存整理时,用户体验会显著恶化。
- 运营成本增加: 为了弥补由于内存使用效率低下造成的容量损失,服务提供商可能不得不部署更多的GPU,从而增加了硬件采购和运维成本。
- 2.5 现有技术在应对碎片化方面的局限性 (为后续解决方案铺垫)
- 为了缓解内存碎片问题,学术界和工业界已经提出了一些技术。你的论文中提到了一个重要的例子:“VLLM Yu et al. (2022)提出的PagedAttention 技术通过类似操作系统中虚拟内存分页的机制,将KV缓存划分为固定大小的块(block),在解码(decode)阶段能够有效管理非连续的显存块,缓解了外部碎片问题。但是,在预填充(prefill)阶段,系统通常需要一次性为输入prompt 的所有 token 分配 KV缓存空间,此时外部碎片仍然是一个显著问题” [cite: 24, 22]。这意味着即使有了PagedAttention这样的技术,预填充阶段对连续内存的需求仍然使碎片化问题难以根除。
- 论文还观察到,一些看似合理的策略,在特定情况下反而可能加剧问题:“负载均衡策略,例如将新请求分散到多个GPU实例上以避免单点过载,虽然有助于降低单个实例的压力和请求被抢占的风险,但这种做法可能会在集群层面加剧显存的碎片化程度” [cite: 22]。因为每个实例都可能只使用了部分显存,剩余的空闲显存分布在不同实例上,难以整合利用。
- 2.6 核心目标:提升GPU显存的有效利用率
- 面对碎片化挑战,我们的核心目标是最大限度地减少无效的内存碎片,从而提升GPU显存的实际有效利用率,容纳更多的并发请求,提高系统整体的吞吐量和成本效益。
- 这自然引出了对更高级的内存管理技术和与内存状态感知的调度策略的需求。例如,你的论文提到,Llumnix系统就将“碎片整理(de-fragmentation)”作为其请求迁移技术的一个关键应用场景,即通过主动迁移请求来整合和释放出更大的连续空闲显存块 [cite: 25]。
第三部分:请求优先级与差异化服务需求 (建议时长:50-60分钟) - 对应论文2.4节
除了物理资源的有效利用,LLM服务系统还需要在逻辑层面处理好不同请求的“重要性”问题,即请求的优先级。
- 3.1 为什么需要优先级处理?
- 在真实的LLM服务环境中,并非所有请求都是“生而平等”的。你的论文明确指出:“源于不同应用场景、不同用户类型或不同付费等级的LLM服务请求,天然地带有不同的紧急程度和服务优先级” [cite: 25]。
- 论文中给出了非常形象的例子:“在线聊天或实时代码助手等交互式应用对延迟非常敏感,其请求应具有较高的优先级;而离线的文档分析、数据标注等批处理任务则对延迟的容忍度较高,可以赋予较低的优先级” [cite: 25]。 这清晰地说明了基于应用场景的优先级划分。此外,付费用户(比如VIP客户)也理应比免费用户享有更高的服务优先级。
- 3.2 传统FCFS策略在优先级处理上的缺失
- 然而,许多现有的,尤其是早期的LLM服务系统,在处理请求优先级方面做得并不好。论文批评道:“然而,许多现有的LLM推理服务系统(尤其是一些早期系统或主要关注单实例性能优化的系统,如vLLM和Orca 的初始版本)在请求调度时往往对所有请求一视同仁,采用简单的FCFS策略,缺乏有效的优先级区分和处理机制” [cite: 25]。
- 这种“一视同仁”的直接后果是什么呢?“这使得高优先级请求很容易被低优先级请求阻塞,其SLO难以得到保障” [cite: 25]。想象一下,一个VIP用户提交了一个紧急的低延迟请求,却因为排在一个普通用户的、非紧急的、耗时长的请求后面而被长时间耽搁,这显然是无法接受的。
- 3.3 一个具备优先级处理能力的系统应具备哪些要素?
- 优先级识别与定义: 系统必须能够识别或被告知每个请求的优先级。这可能通过API参数、用户身份、或者预定义的规则来实现。同时,需要清晰地定义优先级的级别和含义。
- 差异化的调度策略: 调度器在做决策时,必须明确地偏向高优先级请求。例如,高优先级请求应该在等待队列中拥有更短的等待时间,或者能够优先获得GPU等计算资源。
- 抢占机制 (Preemption) - 可能需要: 在资源极度紧张的情况下,为了保障最高优先级请求的SLO,系统可能需要具备抢占(即主动暂停甚至中止)一个或多个正在运行的低优先级请求的能力,以释放出它们占用的资源。
- 性能隔离的保障: 确保高优先级请求的性能不会因为低优先级请求的干扰而下降。这与我们上周讨论的性能隔离问题紧密相连。
- 3.4 实现有效的优先级处理面临的挑战
- 优先级策略的制定: 如何科学地定义优先级的级别?多少个级别合适?不同级别之间应该有多大的区分度?这些策略的制定本身就需要仔细权衡。
- 平衡优先级与公平性,防止“饿死” (Starvation): 如果完全按照绝对优先级来处理,那么低优先级的请求在系统持续繁忙的情况下,可能永远也得不到服务的机会,即发生“饿死”现象。因此,优先级系统还需要设计一些机制来保证基本的公平性,例如,低优先级请求在等待过长时间后可以动态提升其优先级。
- 抢占的开销: 如果引入了抢占机制,那么抢占一个正在运行的LLM请求(特别是其庞大的KV缓存状态)的保存和后续恢复,可能会带来显著的性能开销和实现复杂性。
- 优先级与批处理的协同: 这是个微妙的平衡。高优先级的请求是应该“插队”立即执行(可能会打断当前批次,降低GPU利用率),还是应该等待一个合适的时机加入到一个(可能是混合优先级的)新批次中以期获得更高的批处理效率?这需要调度器进行智能决策。
- 3.5 解决优先级问题的探索方向 (为后续解决方案铺垫)
- 学术界和工业界已经开始积极探索如何在LLM服务中实现有效的优先级处理。
- 你的论文中提到了Llumnix系统的一个有趣做法:“Llumnix Sun et al. (2024)通过引入“虚拟用量(virtual usage)”的概念,并结合请求迁移来实现对高优先级请求的加速处理” [cite: 26]。这是一种通过改变系统对资源占用的“看法”来间接影响调度决策,从而为高优请求“腾出空间”的思路。
- 论文还列举了其他一些相关工作:“类似的,SSJF Qiu et al. (2024)和基于学习排序的调度器 Patke et al. (2024)通过优化请求处理顺序来间接实现优先级效果。SearchAgent-X Yang et al. (2025)则在其调度器中明确引入了优先级感知机制” [cite: 26]。这些例子表明,无论是通过改进请求排序,还是在调度器中内置优先级感知逻辑,都是当前研究的重要方向。
总结与展望 (建议时长:5-10分钟):
- 回顾: 同学们,本周我们深入探讨了LLM服务面临的另外两个核心挑战:由于KV缓存等因素导致的GPU显存碎片化及其对高效利用的阻碍,以及源于不同用户和服务场景的请求优先级处理与差异化服务的需求。我们看到,显存碎片化会直接蚕食系统的有效容量和吞吐量,而缺乏有效的优先级机制则会导致高重要性请求的服务质量无法得到保障。
- 融会贯通: 请大家注意,本周讨论的这两个挑战,与我们前几周学习的负载异构性、执行不可预测性、SLO保障和性能隔离等问题,是紧密交织、相互影响的。例如,请求的异构性和KV缓存的动态性是导致碎片化的主要原因;而有效的优先级处理,本身也需要性能隔离作为支撑,否则高优先级请求依然可能受到低优先级请求的干扰。这些挑战共同构成了LLM服务系统优化这块“硬骨头”。它们也雄辩地证明了,简单的、静态的服务和调度策略是远远不够的。
- 展望未来 (关键转折点): 到目前为止,我们用了数周的时间,非常细致地剖析了LLM服务所面临的“问题”和“挑战”(对应论文的整个第二章)。我相信大家对这些“痛点”已经有了非常深刻的理解。从下一周开始,我们的课程将进入一个激动人心的新阶段:我们将开始系统地学习和探讨学术界与工业界为了攻克这些挑战所提出的各种关键技术和解决方案(这将主要对应论文的第三章:“LLM服务动态调度关键技术”)。我们将看到,动态调度是如何通过运行时请求迁移、智能调度策略、分布式架构等手段,来尝试驯服这些“怪兽”的。
希望大家课后能再次仔细研读论文的2.3和2.4节,并思考一下,如果由你来设计一个既能高效利用显存又能灵活处理优先级的LLM服务系统,你会从哪些方面入手?哪些技术手段可能是有效的?
今天的课就到这里。谢谢大家!
第七周大纲
好的,同学们,我们正式进入第七周的学习。
在过去的三周(第四、五、六周),我们系统地剖析了LLM服务动态调度所面临的核心挑战,包括负载的异构性与执行的不可预测性、SLO保障与性能隔离的难题、GPU资源碎片化问题,以及请求优先级的处理需求。我相信大家对这些“痛点”已经有了非常深刻的认识。我们已经充分理解了为什么传统的、静态的调度策略难以应对这些复杂的局面。
从本周开始,我们的课程将迎来一个重要的转折点:我们将从“分析问题”阶段,全面转向“探索解决方案”阶段。我们将开始系统学习你的论文第三章——“LLM服务动态调度关键技术”——中所阐述的各种前沿技术。这些技术正是为了攻克我们前几周讨论的那些核心挑战而设计的。
本周,我们首先聚焦于其中一项最具变革性的核心技术,对应论文的3.1节:“运行时请求重调度与迁移”。这项技术赋予了服务系统前所未有的灵活性。
第七周:关键技术 (一): LLM服务中的运行时请求重调度与迁移
第一部分:动态调度回顾与运行时自适应的必要性 (建议时长:15-20分钟)
- 首先,让我们再次明确什么是“动态调度”。你的论文在引言部分【[cite: 18]】和后续章节中都强调,动态调度与静态调度的核心区别在于它“强调在系统运行时,根据实时的负载状况、资源利用率、请求特性(如优先级、SLO要求)以及模型执行状态等信息,灵活调整调度决策和资源分配”【[cite: 18]】。
- 我们前面几周分析的各种核心挑战——负载的“多变”和“未知”,对服务质量的“高要求”和“差异化”,物理资源的“宝贵”和“易碎”,逻辑优先级的“复杂”——都雄辩地证明了,试图用一种一成不变的、预先设定的静态策略来完美应对所有情况,几乎是不可能的。系统必须具备在运行时“随机应变”、“自我调整”的能力。
- 运行时请求重调度与迁移 (Runtime Request Rescheduling and Migration),正是实现这种运行时自适应能力的核心支柱之一。你的论文在3.1节开篇就指出,这是“动态调度领域的核心技术之一”【[cite: 27]】。它彻底“打破了传统调度中请求一旦分配给某个计算实例便固定不变的模式”【[cite: 27]】。
第二部分:运行时请求重调度与迁移:基本原理与目标 (建议时长:30-40分钟) - 对应论文3.1节引言部分
- 2.1 核心思想是什么?
- 这项技术的核心思想非常直观,正如论文3.1节所述,它允许系统“在运行时根据全局负载情况、资源利用率、请求优先级或SLO需求等因素,将正在执行或等待队列中的请求从一个模型实例动态地转移到另一个更合适的实例上”【[cite: 27]】。
- 简单来说,就是“不把鸡蛋放在一个篮子里”,并且允许“中途换篮子”。一个请求不再是“从一而终”地绑定在最初分配给它的那个GPU上。
- 2.2 为什么需要这种“中途换篮子”的能力?(动机与目标)
- 我们从前面几周讨论的挑战反过来看,就能理解这项技术的价值所在:
- 负载均衡 (Load Balancing): 当某些GPU实例因为接收了过多请求或遇到耗时长的请求而变得“拥堵不堪”时,可以将一部分请求(无论是等待中的还是正在执行的)迁移到其他相对空闲的GPU上,从而“削峰填谷”,提升整个集群的资源利用率和响应速度。
- 资源碎片整理 (Resource Defragmentation): 我们上周重点讨论了GPU显存碎片化的问题。通过主动地将某些GPU上的请求“请走”,可以腾出大块连续的显存空间,用于接纳那些需要大量初始显存的新请求(比如长prompt的预填充)。
- 保障SLO/QoS: 如果一个高优先级、对延迟敏感的请求,不幸落入一个拥挤或者受到“邻居”干扰的GPU上,导致其SLO面临风险,系统可以将它迁移到一个更“清净”、资源更充裕的环境中。
- 优先级处理: 当更高优先级的请求到达,但当前没有足够资源时,除了等待,系统还可以考虑将一些正在运行的低优先级请求迁移走,为高优请求“腾位置”。
- 辅助自动伸缩 (Auto-scaling) 以实现节能降本: 在业务低谷期,可以将分散在多个GPU上的少量请求整合、迁移到少数几个GPU上集中处理,然后将那些完全空闲的GPU实例关闭或休眠,从而节省能源和成本。当业务高峰来临,新启动了GPU实例后,也可以从繁忙实例迁移部分负载过去,使其快速“热起来”。
- 故障规避/容错: 在更高级的系统中,如果能检测到某个GPU实例即将发生故障或性能异常,可以预先将其上的请求迁移走,避免服务中断。
- 我们从前面几周讨论的挑战反过来看,就能理解这项技术的价值所在:
- 2.3 重调度/迁移的对象范围?
- 相对简单的是迁移那些还在等待队列中的请求,因为它们还没有开始执行,没有复杂的运行时状态。
- 更具挑战性也更具威力的是迁移那些正在执行中的请求,我们称之为“实时迁移”或“活迁移”(Live Migration)。这需要精巧的技术来保证迁移过程的低延迟和状态一致性。
第三部分:KV缓存的高效迁移机制 (建议时长:60-70分钟) - 对应论文3.1.1节
既然要迁移正在执行的LLM请求,那么最核心、最棘手的问题就是如何处理它庞大而动态的“状态”——KV缓存。
- 3.1 KV缓存在请求迁移中的核心地位与挑战
- 论文3.1.1节开宗明义:“LLM 推理请求的核心状态在于其KV缓存”【[cite: 28]】。这个KV缓存记录了到当前为止所有已生成词元的注意力中间结果,是请求能继续往下生成的基础。
- 同时,论文也指出了迁移KV缓存的难点:“由于KV缓存可能非常庞大(尤其对于长序列或多轮对话),其迁移效率直接决定了请求重调度的可行性和性能”【[cite: 28]】。如果迁移一个KV缓存需要花费很长时间,或者导致请求长时间停顿,那么迁移本身带来的好处就可能被抵消甚至反超。
- 3.2 迁移KV缓存面临的主要技术挑战:
- 体积巨大 (Large Size): 我们已经知道KV缓存动辄数十GB。通过网络或者PCIe总线在不同GPU实例之间(甚至在同一机器的不同GPU之间)传输如此大量的数据,本身就需要可观的时间,并可能消耗大量的传输带宽。
- 状态动态变化 (Dynamic Nature): 对于一个正在活跃生成词元的请求,它的KV缓存几乎在每个推理步骤(每个新词元的生成)之后都会发生变化(追加新的K、V对)。如何在迁移过程中捕获到一个一致的、有效的KV缓存状态是一个难题。
- 最小化停顿时间 (Minimizing Downtime): 对于“实时迁移”,我们希望请求的处理过程(即词元生成)因迁移而暂停的时间尽可能短,最好用户无感知。过长的停顿会严重影响用户体验,违背迁移的初衷。
- 3.3 Llumnix系统的高效实时迁移机制剖析 (论文中的核心案例)
- 你的论文中重点介绍并高度评价了Llumnix系统在KV缓存迁移方面的创新。论文提到:“Llumnix 系统 Sun et al. (2024)提出了一种创新的LLM请求实时迁移(live migration)机制”【[cite: 28]】。
- 巧妙利用KV缓存的“仅追加 (append-only)”特性:
- 这是Llumnix迁移机制的核心洞察。论文解释道:“该机制巧妙地利用了LLM推理过程中KV缓存通常是“仅追加 (append-only)”的特性——即在生成新 token时,只会向已有的KV缓存中追加新的键值对,而不会修改历史部分”【[cite: 28]】。这意味着,一旦某个词元的K、V向量被计算出来并存入缓存,它就不会再被改变了。
- 流水线式的复制过程 (Pipelined Copying):
- 基于这个“仅追加”特性,Llumnix可以做到“边计算,边复制”。论文描述了这个过程:“基于此,Llumnix可以在源实例继续为目标请求计算新 token 的同时,将该请求已经生成的历史KV缓存块以流水线的方式复制到目标实例”【[cite: 28]】。也就是说,当请求还在源GPU上生成新的词元时,系统就已经开始将那些“固定不变”的历史KV缓存数据块,一块接一块地、像流水线一样预先拷贝到目标GPU上。
- 极短的“停止-复制-启动”暂停 (Minimizing Stop-the-World Pause):
- 由于大部分KV缓存数据已经在请求仍在运行时被预先拷贝了,所以真正需要暂停请求计算的时间就非常短了。论文指出:“仅在迁移的最后阶段,才需要短暂停止请求的计算,以拷贝最后一次迭代生成的少量KV缓存,从而实现了近乎零的迁移停机时间,并且该停机时间与请求的序列长度基本无关”【[cite: 28]】。这个“最后一次迭代生成的少量KV缓存”通常只包含最近一个或几个词元的状态,数据量很小,拷贝极快。因此,整个迁移过程对请求执行的“打断”可以做到非常短暂,几乎不影响用户感知,而且这种短暂的停顿时间不会因为请求已经生成了很长的序列(即历史KV缓存很大)而显著增加。
- 论文总结道,这种高效的迁移机制是Llumnix系统能够实现其多种动态调度场景(如负载均衡、碎片整理等)的基础【[cite: 28]】。
- 3.4 其他系统在状态迁移方面的探索 (简要提及)
- 高效的状态迁移是实现灵活服务的一个普遍需求,其他一些系统也从不同角度进行了探索。
- 论文提到:“ServerlessLLM Gao et al. (2024)在其为无服务器LLM推理设计的系统中也支持实例间的实时迁移,以实现低延迟和资源优化”【[cite: 29]】。这表明实时迁移技术在其他新兴的LLM服务范式中也得到了应用。
- 另外,论文还提及QLM系统在执行请求“驱逐”(eviction)操作(例如,为了给高优先级请求腾出资源而将一个正在运行的低优先级请求暂停并移出GPU)时的一个做法:“QLM系统Agrawal et al. (2024)在执行请求驱逐(eviction)操作以保障高优先级请求的SLO时,会将待驱逐请求的KV缓存迁移到CPU主存,并通过异步 GPU 内存复制技术来隐藏迁移带来的性能开销”【[cite: 29]】。虽然这种迁移的目标位置(CPU主存)和目的(通常是临时保存以待后续恢复,而非立即在另一GPU上继续执行)与Llumnix的跨GPU实例实时迁移有所不同,但它同样涉及到对KV缓存这一核心状态的移动和管理。
- 这些例子共同说明,学术界和工业界都在努力寻求以尽可能小的代价、尽可能不影响服务连续性的方式来移动LLM请求的核心状态,从而为上层更灵活、更智能的调度策略提供更大的施展空间【[cite: 29]】。
第四部分:迁移技术的应用:跨实例负载均衡与资源整合 (建议时长:30-40分钟) - 对应论文3.1.2节
拥有了高效的请求(特别是其KV缓存)迁移能力之后,服务系统就能“解锁”许多之前难以实现或效果不佳的动态优化策略。论文3.1.2节重点介绍了两个主要应用场景:
- 4.1 应用一:更主动、更精细的跨实例负载均衡
- 论文指出:“拥有了高效的请求迁移能力后,系统便可以实现更主动和精细的跨实例负载均衡”【[cite: 30]】。
- 具体是如何实现的呢?“当某个实例负载过高,可能导致请求长时间排队或频繁抢占时,系统可以将部分请求(如低优先级请求或对延迟不敏感的请求)迁移到其他负载较轻的实例上,从而均衡整个集群的负载,减少性能瓶颈”【[cite: 30]】。这就像一个智能的交通调度系统,当发现某条路堵车了,就主动引导一部分车辆改道去其他畅通的路上。
- 4.2 应用二:对抗GPU显存碎片化,实现资源整合
- 我们上周详细讨论过GPU显存碎片化的危害。请求迁移为解决这个问题提供了一个强有力的武器。论文写道:“同时,请求迁移也是实现资源整合、对抗GPU显存碎片化的有效手段”【[cite: 30]】。
- 其背后的机制是:“系统可以通过主动迁移策略,将某些实例上的运行中请求“搬走”,从而在这些实例上腾出较大的连续空闲显存块”【[cite: 30]】。想象一下,通过把停车场里几辆位置不佳的小车挪走,就能空出一块能停大巴的完整车位。
- 这样做的好处是显而易见的:“这些整合出来的空间可以用于接纳新的、需要大量初始显存的请求(如长prompt的预填充),从而显著降低其排队延迟”【[cite: 30]】。
- 论文明确提到,Llumnix系统就将负载均衡和碎片整理 (de-fragmentation) 作为其请求迁移技术的两个主要应用场景,并通过实验证明了其有效性【[cite: 30]】。
- 4.3 其他具有相似目标的系统思路 (补充视角)
- 论文在这一节的末尾,也提及了Sarathi-Serve和DistServe这两个系统【[cite: 31]】。虽然它们可能不直接进行像Llumnix那样复杂的运行时KV缓存跨实例实时迁移,但它们也通过各自独特的设计(如Sarathi-Serve的分块预填充和无停顿调度,DistServe的预填充/解码分离架构)来优化批处理内部的负载均衡,或者在宏观层面实现计算负载的均衡和资源专业化,从而避免不同计算模式间的直接干扰【[cite: 31]】。这从侧面印证了,无论是通过何种技术路径,实现高效的负载分布和资源整合,都是LLM服务系统追求的关键目标。
总结与展望 (建议时长:5-10分钟):
- 回顾: 同学们,今天我们学习了LLM动态调度的一项核心使能技术——运行时请求重调度与迁移。我们重点剖析了其成功的关键在于高效的KV缓存迁移机制,并以Llumnix系统为例,理解了如何利用KV缓存的“仅追加”特性实现近乎零停机的实时迁移。我们还看到了这项技术在实现跨实例负载均衡和GPU显存碎片整理等重要优化目标上的巨大潜力。
- 强调: 运行时请求迁移技术,通过赋予系统在运行时动态调整请求物理位置的能力,直接为应对我们前几周讨论的诸多核心挑战(如负载不均、资源碎片、SLO保障等)提供了强有力的手段。它是从“静态”服务走向“动态”服务的一个重要里程碑。
- 展望: 掌握了这种强大的“乾坤大挪移”能力之后,调度系统还需要“智慧”来决定何时迁移、迁移谁、迁移到哪里。因此,在下周(第八周),我们将继续学习论文3.2节的内容,探讨动态调度中的另一些关键技术——面向LLM特性的智能调度策略,例如基于预测的调度优化和抢占式调度。这些策略将与请求迁移技术相辅相成,共同提升LLM服务的智能化水平和运行效率。
今天的课就到这里。请大家课后务必仔细阅读论文的3.1节,深刻理解KV缓存迁移的原理和意义。谢谢大家!
第八周大纲
好的,我们来规划第八周的课程大纲。
根据我们之前的学习路径和你的论文结构,继第七周学习了“运行时请求重调度与迁移”之后,第八周我们将继续深入探讨论文第三章中的关键技术,重点聚焦于3.2节——“面向LLM特性的智能调度策略”。这部分将介绍调度器如何利用LLM的特性和预测信息来做出更“聪明”的决策。
第八周:关键技术 (二): 面向LLM特性的智能调度策略
核心目标:
- 理解为什么需要针对LLM特性设计专门的智能调度策略。
- 深入学习基于预测的调度优化方法,特别是如何利用对输出长度等特征的预测来改进调度性能。
- 探讨抢占式调度在LLM服务中的应用、必要性、实现挑战及公平性考量。
- (根据教学大纲,3.2.3节“面向自动伸缩的调度机制”我们可以在本周初步引入,或根据时间安排调整到后续与自动伸缩更集中的讨论中)。
第一部分:回顾与智能调度的引入 (建议时长:15-20分钟)
- 1.1 上周内容回顾: 简要回顾运行时请求迁移的核心思想、KV缓存迁移的关键技术及其在负载均衡和碎片整理中的应用。强调请求迁移为“智能决策”提供了执行手段。
- 1.2 为什么需要“智能”调度策略?
- 仅有迁移能力是不够的,还需要“大脑”来决定何时、何地、为何以及如何迁移或调度。
- 传统调度策略(如FCFS、简单轮询)无法充分利用LLM的特性,也难以应对其独有的挑战(异构性、不可预测性等)。
- “智能”体现在调度器能够更好地理解请求特征、预测未来行为、并根据预设目标(如降低延迟、提高吞吐量、保障SLO)做出优化决策。
- 1.3 本周焦点: 论文3.2节将介绍几种典型的智能调度思路,我们本周重点关注其中的基于预测的调度和抢占式调度。
第二部分:基于预测的调度优化 (建议时长:50-60分钟) - 对应论文3.2.1节
LLM执行的不可预测性,特别是输出序列长度的未知性,是调度面临的一大难题。如果能够对请求的某些关键特征进行有效预测,无疑将为调度决策提供宝贵信息。
- 2.1 预测的核心目标与意义
- 目标: 预测LLM请求的关键执行特征,最常见的是输出序列长度,有时也包括大致的计算量或执行时间。
- 意义:
- 克服不可预测性带来的调度盲目性。
- 使得一些理论上高效的调度策略(如SJF/SRTF)能够近似应用。
- 为批处理优化、资源预留、SLO预估等提供输入。
- 论文指出:“如果能够对请求的某些关键特征(如大致的输出长度或计算量)进行有效预测,无疑将为调度决策提供宝贵信息” [cite: 32]。
- 2.2 如何进行预测?—— 轻量级代理模型 (Proxy Models)
- 直接运行一遍LLM来获取长度显然不现实。
- 常用方法:使用一个更小、更轻量的模型(如小型的BERT模型或其他机器学习模型)来根据请求的prompt内容或其他元数据,快速预测其可能的输出长度。
- 论文提及的SSJF和ELIS系统均采用此思路 [cite: 32]。SSJF (Speculative Shortest Job First) 和 ELIS (Efficient LLM Iterative Scheduling System) 都使用轻量级代理模型预测LLM请求的输出序列长度 [cite: 32, 47]。
- 2.3 基于预测长度的调度策略应用:近似SJF/SRTF
- SJF (Shortest Job First) / SRTF (Shortest Remaining Time First): 理论上能最小化平均作业完成时间 (JCT) 或平均等待时间。
- 在获得预测的输出长度后,调度器可以将请求近似地按照“最短作业优先”的原则进行排序和调度。
- 效果:
- SSJF的实验结果表明,其能够将平均JCT降低30.5%至39.6%,并将系统吞吐量提升2.2至3.6倍 [cite: 32]。
- ELIS也报告了其ISRTF(Iterative Shortest Remaining Time First)调度策略可将平均JCT降低高达19.6% [cite: 32, 47]。
- 2.4 基于学习排序 (Learning to Rank) 的调度器
- 另一种思路是不追求预测每个请求的精确输出长度,而是学习预测一个批次内各个请求输出长度的相对排序。
- 论文介绍了Fu等人提出的基于学习排序的调度器 Patke et al. (2024) [cite: 33, 49]。该方法训练一个模型来预测批内请求输出长度的相对顺序 [cite: 33]。
- 这种相对排序信息同样可以有效地指导SJF类型的调度,并且可能比预测绝对长度更鲁棒,实现成本也更低 [cite: 33]。
- 效果: 据报道,该方法在聊天机器人服务场景下可将延迟降低2.8倍,在合成数据生成任务中可将吞吐量提升6.5倍 [cite: 34]。
- 2.5 预测的挑战与考量
- 预测模型的准确性: 预测不准可能导致错误的调度决策,甚至性能劣化。
- 预测模型的通用性: 能否适应不同类型、不同领域的输入请求。
- 预测本身的开销: 预测过程不能太耗时,否则得不偿失。理想的预测模型应轻量、快速 [cite: 34]。
- 对动态变化的适应性: 用户行为和数据分布可能随时间变化,预测模型可能需要定期更新。
第三部分:抢占式调度与公平性保障 (建议时长:50-60分钟) - 对应论文3.2.2节
在某些场景下,仅仅通过优化排队顺序或迁移可能不足以满足紧急需求,此时,更“激进”的抢占式调度就显得必要了。
- 3.1 为什么需要抢占式调度 (Preemptive Scheduling)?
- 保障高优先级请求的SLO: 当更高优先级的请求到达,但系统资源已被低优先级请求占用时,可以通过抢占来立即释放资源。
- 应对突发的系统过载或SLO违约风险: 当系统检测到某些正在运行的请求可能导致自身或其他请求的SLO即将违约时,可以主动中断(抢占)一个或多个当前正在运行的低优先级或长耗时请求。
- 论文指出,抢占式调度成为一种必要的机制,用以保障高优先级请求的SLO或应对突发的系统过载 [cite: 35]。
- 3.2 抢占的实现方式与挑战
- 如何“抢占”一个LLM请求?
- 关键在于处理其KV缓存状态。被抢占的请求的KV缓存需要被保存下来,以便后续能够从断点处恢复执行。
- 保存和恢复KV缓存(可能涉及从GPU到CPU甚至磁盘的传输)会带来显著的开销。
- Llumnix的间接抢占: 论文提到,Llumnix虽然不直接称其为抢占,但其通过将高优先级请求周围的其他请求迁移走,实际上为高优请求动态地“清理”出一个低干扰的执行环境,达到了类似抢占的效果 [cite: 36]。其本身的动态重调度能力也隐含了对导致拥塞或性能下降的请求的“驱逐”能力 [cite: 36]。
- QLM系统的请求驱逐机制: QLM系统支持请求驱逐:当其RWT(Request Waiting Time)估计器检测到潜在的SLO违规时,全局调度器可以将一个正在运行的请求组从GPU的运行批次中移出,放回等待队列,以便为更紧急的请求组腾出空间 [cite: 37]。
- 如何“抢占”一个LLM请求?
- 3.3 公平性保障 (Fairness Considerations)
- 抢占虽然能保障高优请求,但也可能导致一个严重的问题:低优先级请求“饿死” (Starvation)。如果高优先级请求持续不断,低优先级请求可能永远得不到执行机会。
- 因此,调度策略需要在抢占的“果断性”和系统的整体“公平性”之间取得平衡 [cite: 37]。
- 差额轮询 (Deficit Round Robin - DRR) 思想的应用:
- 论文介绍了Cao等人提出的DLPM (Deficit Longest Prefix Match) 和D2LPM算法 [cite: 38]。这些算法借鉴了传统网络调度中的DRR思想,通过为每个客户端/任务维护一个“差额计数器”来控制其资源获取,旨在保证公平性的同时,尽可能利用LLM对话中常见的前缀缓存局部性来提高效率 [cite: 38]。
- 目标是在保障每个任务都能获得一定服务机会的前提下,尽可能提升整体性能。
- 3.4 抢占决策的复杂性
- 何时抢占? (触发条件:高优请求到达?SLO告急?)
- 抢占谁? (选择哪个或哪些正在运行的低优请求?选择“代价”最小的?)
- 抢占到什么程度? (是完全中止,还是只是暂停并保存状态?)
- 这些决策都需要调度器具备高度的智能和对系统全局状态的感知。
第四部分:初步探讨面向自动伸缩的调度机制 (建议时长:10-15分钟, 可根据进度调整) - 对应论文3.2.3节
动态调度机制,特别是请求迁移,可以与云环境下的自动伸缩策略紧密配合,以提升资源利用效率和弹性。
- 4.1 自动伸缩 (Auto-scaling) 的概念与目标
- 根据实际负载动态调整服务实例的数量(GPU数量)。
- 目标:在满足性能SLO的前提下,最小化资源成本。
- 4.2 调度与自动伸缩的协同
- 缩容 (Scale-in): 当需要减少实例数量时,调度器可以将待关闭实例上仍在运行的请求主动迁移到其他将继续运行的实例上,从而加速该实例的“排空”(drain out),使其能更快地被回收,节省成本 [cite: 39]。Llumnix的一个重要应用场景就是辅助自动伸缩 [cite: 39]。
- 扩容 (Scale-out): 当系统检测到负载增加,需要增加新的实例时,调度器可以将其他高负载实例上的部分请求迁移到新启动的实例上,使其能更快地参与服务,分担负载压力,避免新实例长时间空闲或冷启动 [cite: 39]。
- 4.3 协同的好处
- 更快速、更平滑地响应负载变化。
- 避免单纯依赖反应式伸缩(即等到过载或空闲发生后再调整)可能带来的资源浪费或服务质量下降 [cite: 40]。
- 论文中Llumnix的评估表明,通过这种调度与伸缩的配合,可以在保证相似尾延迟性能的前提下,节省高达36%的资源成本 [cite: 39]。Chiron系统也提出了一种综合考虑队列积压、实例利用率及SLO符合情况进行伸缩决策的分层自动伸缩思路 [cite: 40]。
总结与展望 (建议时长:5-10分钟)
- 回顾: 本周我们学习了两种核心的面向LLM特性的智能调度策略:基于预测的调度优化(通过预测输出长度等来实现近似SJF/SRTF或学习排序)和抢占式调度(通过中断低优请求来保障高优请求或应对系统过载,同时需要考虑公平性)。我们还初步探讨了调度与自动伸缩的协同。
- 核心思想: 这些智能策略的共同点在于,它们试图更深入地“理解”LLM请求的特性和系统的实时状态,从而做出比传统简单策略更优的调度决策。
- 展望: 掌握了请求迁移能力和这些智能调度策略后,如何将它们有效地组织在一个可扩展的系统架构中呢?下周(第九周),我们将继续学习论文3.3节的内容,探讨LLM服务中分布式调度系统架构的设计,看看一个现代化的LLM动态调度系统在宏观层面是如何构建的。
这个大纲详细地覆盖了论文3.2节的主要内容,保持了理论研究的深度,并为后续学习分布式架构做了铺垫。
第二部分
好的,同学们,我们继续第八周的课程。
上周我们学习了“运行时请求重调度与迁移”这一关键技术,它赋予了LLM服务系统在运行时动态调整请求物理位置的能力,为负载均衡、碎片整理等优化提供了强有力的执行手段。但仅仅拥有“挪动”请求的能力还不够,调度系统还需要更“聪明”的“大脑”来决定请求的执行顺序和时机。
因此,本周我们聚焦于论文3.2节所阐述的“面向LLM特性的智能调度策略”。今天,我们将首先深入探讨其中的第一种思路,即3.2.1节的内容:“基于预测的调度优化”。我们在第四周学习核心挑战时,深刻体会到LLM执行的“不可预测性”(尤其是输出长度的未知)是调度面临的一大难题。那么,如果我们能够对请求的某些行为进行一定程度的“未卜先知”,是否就能让我们的调度决策更加有的放矢呢?这就是我们今天要探讨的核心问题。
第二部分:基于预测的调度优化 (建议时长:50-60分钟) - 对应论文3.2.1节
引言:
想象一下,如果调度器在面对一堆等待处理的LLM请求时,能够大致判断出哪些请求可能是“快餐”(很快就能完成),哪些可能是“大餐”(需要较长时间),那么它就能够更合理地安排“就餐顺序”,从而让整个“餐厅”的顾客(用户)平均等待时间更短,满意度更高。这就是基于预测的调度优化的基本思想——试图通过对未来进行有根据的猜测,来弥补LLM执行的不可预测性。
2.1 预测的核心目标与意义
- 2.1.1 我们究竟想预测什么?
- 在LLM服务的调度场景下,我们最关心的、最希望能够预测的,通常是每个请求的输出序列长度 [cite: 14]。因为输出长度直接关系到请求的总计算量、KV缓存的最终大小以及总的执行时间。
- 有时,对输出长度的预测也可以被进一步转化为对其大致计算量或执行时间的预测 [cite: 14]。
- 2.1.2 为什么预测对调度如此重要?
- 克服因不可预测性带来的调度“盲目性”: 正如我们在第四周所学,LLM输出长度的未知性,使得调度器在处理请求时如同“盲人摸象”。预测,哪怕不是百分之百准确,也能为调度器提供一双“眼睛”,让它对请求的潜在行为有所感知。
- 使得理论上高效的调度策略得以近似应用:
- 经典的调度理论中,有一些被证明在特定目标下(比如最小化平均作业完成时间)是最优或近似最优的策略,例如我们多次提到的SJF(最短作业优先)或SRTF(最短剩余时间优先)。
- 但这些策略都有一个共同的前提:必须预先知道每个作业的执行长度。在LLM的场景下,直接应用它们是不可能的。然而,如果我们能够预测出每个请求的大致“长度”(例如,预测的输出词元数),我们就可以近似地实现SJF或SRTF这类高效策略。
- 为其他系统优化提供关键输入:
- 更智能的批处理 (Batching): 知道了请求可能的长度,有助于调度器构建更优化的批次。例如,可以将预测长度相近的请求合并处理以减少批内差异,或者根据预测长度将请求分到不同的“桶”或队列中(例如你的论文中提及的Multi-Bin Batching技术 [cite: 15, 35, 50])。
- 更精准的资源预留: 对输出长度的预测,有助于更准确地估算请求在其生命周期内(尤其是KV缓存)所需的资源量,从而进行更合理的资源预留,避免浪费或不足。
- 更可靠的SLO预估与保障: 如果我们能预测一个请求大致需要执行多久,就能更好地判断它是否有可能满足其延迟SLO,甚至可以基于预测主动进行干预。
- 你的论文在3.2.1节开头就精辟地指出了这一点:“LLM 执行的不可预测性,特别是输出序列长度的未知性,是调度面临的一大难题。如果能够对请求的某些关键特征(如大致的输出长度或计算量)进行有效预测,无疑将为调度决策提供宝贵信息” [cite: 14]。
2.2 如何进行预测?—— 轻量级代理模型 (Proxy Models) 的应用
- 2.2.1 直接测量的不可行性: 我们显然不能为了预测一个请求会生成多长,就先完整地把它用LLM跑一遍——那样的话,预测本身就失去了意义,因为我们已经知道了结果,并且付出了全部的计算代价。
- 2.2.2 代理模型的核心思路:
- 业界的普遍做法是,训练一个远比主LLM模型更小、更快、计算开销也低得多的“代理模型”(Proxy Model,有时也称作Surrogate Model)。
- 这个代理模型以用户输入的prompt(或者从prompt中提取的某些特征)作为输入,它的输出就是对该prompt在主LLM上可能产生的输出序列长度的一个预测值。
- 论文中的实例佐证: 你的论文提到,“一些研究工作正朝着这个方向努力。例如,SSJF(Speculative Shortest Job First) Qiu et al. (2024)和ELIS (Efficient LLM Iterative Scheduling System) Choi et al. (2025) 均采用了一个轻量级的代理模型(如小型BERT 模型)来预测LLM请求的输出序列长度” [cite: 14, 32, 48]。这里的Qiu等人2024年的工作就是论文参考文献中的[4](对应我们上下文的源[89]),Choi等人2025年的工作是参考文献中的[11](对应我们上下文的源[95])。
- 2.2.3 代理模型的训练:
- 代理模型是如何学会预测的呢?它通常是在大量历史数据上进行监督学习训练得到的。这些历史数据由成对的(用户prompt,该prompt在主LLM上实际生成的输出长度)样本组成。
- 代理模型的目标,就是从这些数据中学习到prompt的某些文本特征(比如长度、关键词、句式结构等)与主LLM最终生成长度之间的潜在关联模式。
2.3 基于预测长度的调度策略应用:近似SJF/SRTF的威力
一旦我们拥有了能够预测输出长度的代理模型,就可以尝试应用那些理论上非常高效的调度策略了。
- 2.3.1 再次回顾SJF/SRTF策略:
- SJF (Shortest Job First - 最短作业优先): 这是一个非抢占式策略。一旦一个作业(在这里指一个LLM请求)开始执行,它就会一直运行到完成。SJF会按照作业的执行时间(我们现在用预测的输出长度来近似)从小到大进行调度。
- SRTF (Shortest Remaining Time First - 最短剩余时间优先): 这是SJF的抢占式版本。在任何时刻,如果一个新的作业到达,并且它预测的总执行时间小于当前正在执行的作业预测的剩余执行时间,那么当前作业就会被抢占(暂停),新作业优先执行。
- 理论上的优越性: 在满足某些假设条件(例如所有作业同时到达,或可以准确预知执行时间)下,SJF/SRTF策略被证明能够最小化平均作业完成时间 (Average Job Completion Time - JCT) 或平均等待时间。
- 2.3.2 如何利用预测近似SJF/SRTF?
- 当一个新请求到达时,系统首先调用代理模型预测其输出长度。
- 然后,调度器就可以将这个预测长度作为该请求“作业长度”的估计值。
- 对于SJF,调度器可以简单地将等待队列中的请求按照预测长度升序排列,然后依次派发给空闲的GPU。
- 对于SRTF,情况会更复杂一些,调度器不仅需要知道新请求的预测总长度,还需要能够估算当前正在执行的请求还剩下多少(预测的)长度才能完成,然后进行比较和可能的抢占。
- 2.3.3 显著的性能提升(来自论文的例证):
- 这些基于预测的近似SJF/SRTF策略,在实践中取得了令人鼓舞的效果。你的论文中明确提到:
- “基于预测的长度,它们可以实现近似最短作业优先(SJF)或最短剩余时间优先(SRTF)的调度策略” [cite: 14]。
- 关于SSJF系统:“实验结果也表明,SSJF能够将平均JCT降低30.5%至39.6%,并将系统吞吐量提升2.2至3.6倍” [cite: 14, 32]。这是一个非常显著的性能提升!
- 关于ELIS系统:“ELIS也报告了高达19.6%的JCT降低” [cite: 14, 48]。
- 这些数据有力地证明了,即使预测不完美,基于预测的调度也比简单的、不感知请求长度的策略(如FCFS)要优越得多。
- 这些基于预测的近似SJF/SRTF策略,在实践中取得了令人鼓舞的效果。你的论文中明确提到:
2.4 另一种思路:基于学习排序 (Learning to Rank) 的调度器
除了预测每个请求的绝对输出长度之外,还有一种更“取巧”但可能同样有效的方法:不预测具体数字,而是学习预测请求之间的“相对快慢”。
- 2.4.1 从预测“绝对值”到预测“相对顺序”:
- 精确预测每个请求会生成多少个词元,难度较大,且容易出错。
- 一个思路是,我们是否可以退而求其次,不要求知道每个请求到底有多长,只需要知道在一组请求中,哪一个可能比另一个更短?
- 2.4.2 学习排序 (Learning-to-Rank - LTR) 方法:
- 你的论文介绍了一种相关的工作:“另一项相关工作是Fu等人提出的基于学习排序(Learning to Rank)的调度器 Patke et al. (2024)” [cite: 14, 33, 49]。这里Patke等人2024年的工作是论文参考文献中的[16]或[6](对应我们上下文的源[101]或[91],根据作者和年份判断应为[101])。
- 论文解释道:“该方法并不追求预测每个请求的精确输出长度,而是训练一个模型来预测一个批次内各个请求输出长度的相对排序” [cite: 14, 33, 49]。也就是说,这个模型学会的是判断“请求A的输出大概率比请求B的输出短”。
- 2.4.3 优势及性能表现:
- 这种相对排序信息,虽然没有给出具体的长度值,但论文指出:“这种相对排序信息同样可以有效地指导 SJF类型的调度,避免了精确预测的困难” [cite: 14, 33]。例如,调度器在选择下一个要执行的请求时,可以总是挑选那个被模型预测为“相对更短”的请求。这种方法可能对绝对预测值的误差不那么敏感,因此可能更鲁棒。
- 其性能如何呢?论文报告称:“据报道,该方法在聊天机器人服务场景下可将延迟降低2.8倍,在合成数据生成任务中可将吞吐量提升 6.5倍” [cite: 14, 33, 49]。这同样是非常可观的收益。
- 2.4.4 与“多桶批处理” (Multi-Bin Batching) 的关联:
- 论文还提及了另一项利用预测长度信息的技术:“此外,Multi-Bin Batching Fu et al. (2024)也是一种利用预测长度信息将请求分组到不同“箱子”(bin)中进行批处理,以期优化整体吞吐量的技术” [cite: 15, 35, 50]。这里Fu等人2024年的工作是参考文献中的[12](对应我们上下文的源[96]或[97],ICLR ‘24)。这种方法也是依赖某种形式的长度预测(可能是绝对长度,也可能是长度区间)来将特征相似的请求归类处理,从而提高批处理的效率。
2.5 预测技术自身的挑战与需要权衡的因素
虽然基于预测的调度优化展现了巨大的潜力,但它并非“银弹”,自身也面临着一些需要仔细考量的挑战和权衡。
- 2.5.1 预测模型的准确性 (Accuracy):
- 这是最核心的因素。如果代理模型或排序模型的预测结果与实际情况偏差很大,那么基于这些错误预测做出的调度决策,不仅可能无法带来预期的性能提升,甚至可能比不用预测时更糟糕。
- 如何评估和持续保证预测模型的准确性,是一个重要的问题。
- 2.5.2 预测模型的通用性与适应性 (Generality and Adaptability):
- 一个在特定数据集上训练出来的预测模型,能否很好地泛化到各种不同类型、不同主题、不同语言的用户prompt上?这是一个考验。
- 此外,如果底层的LLM模型本身发生了更新迭代(比如从GPT-4换到GPT-5),或者用户的查询模式和兴趣点随时间发生了变化,那么之前训练的预测模型可能就会“过时”,其预测准确率会下降,这时就需要对预测模型进行重新训练或更新。
- 2.5.3 预测本身的开销 (Overhead of Prediction):
- 调用代理模型进行预测,这个过程本身也是需要消耗计算时间和资源的(尽管远小于主LLM)。这个额外的开销必须足够小,才不至于“得不偿失”,即预测带来的调度收益要能远大于预测本身的成本。
- 正如你的论文总结的那样:“这些基于预测的调度方法的核心在于预测模型的准确性、通用性以及预测本身的开销。一个理想的预测模型应该轻量、快速,并且对不同类型和分布的输入请求都具有较好的预测精度” [cite: 15]。
- 2.5.4 对预测错误的鲁棒性 (Robustness to Prediction Errors):
- 调度策略在面对不完全准确的预测时,其行为是否能够“优雅降级”?也就是说,即使预测有一定误差,调度结果也不至于太差。
- 论文在这里给出了一个积极的观察:“相对排序预测可能比绝对长度预测更具鲁棒性,且实现成本更低” [cite: 15]。这提示我们,在某些情况下,追求完美的绝对值预测可能不如追求一个更稳定、对误差容忍度更高的相对关系预测。
总结与过渡 (2-3分钟):
- 回顾: 同学们,今天我们详细探讨了“基于预测的调度优化”这一重要的智能调度策略。我们看到,通过使用轻量级的代理模型来预测LLM请求的输出序列长度,或者通过学习排序模型来预测请求长度的相对顺序,我们可以近似地实现像SJF这样理论上高效的调度策略,并确实在实践中(如SSJF、ELIS等系统)取得了显著的平均延迟降低和吞吐量提升。
- 核心权衡: 但我们也认识到,这种预测能力并非没有代价,它依赖于预测模型的准确性、通用性,并且预测过程本身也会引入一定的开销。如何在这些因素之间进行权衡,是设计和应用此类技术的关键。
- 展望: 基于预测的调度主要优化的是请求的执行顺序。但有时,仅仅改变顺序可能还不够,我们可能需要更“主动”的手段,例如,当一个非常重要的请求到达,但资源都被不那么重要的请求占着时,我们是否可以“打断”那些不重要的请求呢?这就引出了我们接下来要讨论的另一种重要的智能调度策略:抢占式调度。
今天的第二部分内容就到这里。谢谢大家!
第三部分
好的,同学们,我们继续第八周关于“面向LLM特性的智能调度策略”的探讨。
在上一部分(第二部分),我们详细学习了“基于预测的调度优化”,了解了如何通过预测LLM请求的输出长度等特征,来近似实现像SJF这样的高效调度策略,从而优化请求的执行顺序。这种方法的核心在于“规划”和“排序”。
但是,在某些情况下,仅仅优化等待队列中请求的顺序可能还不够。想象一下,一个非常重要的、对延迟有极高要求的VIP请求到来了,但此刻所有的GPU资源都被一些不那么紧急的、可能还在运行长任务的普通请求占用了。这时候,我们是让VIP请求继续等待,还是应该采取更“果断”的措施呢?这就引出了我们接下来要深入探讨的另一种关键的智能调度策略,对应你的论文3.2.2节:“抢占式调度与公平性保障”。
第三部分:抢占式调度与公平性保障 (建议时长:50-60分钟) - 对应论文3.2.2节
引言:
如果说基于预测的调度是一种“运筹帷幄”的智慧,那么抢占式调度则更像是一种在关键时刻“当机立断”的魄力。它涉及到在运行时主动中断一个或多个正在执行的任务,以便为更重要的任务腾出资源。这种策略虽然强大,但也引入了新的复杂性和需要仔细权衡的因素,特别是关于“公平性”的问题。
3.1 为什么需要抢占式调度 (Preemptive Scheduling)?
- 3.1.1 非抢占式策略的局限性:
- 即使我们通过预测将请求队列排得再好(比如,短请求在前),一旦一个(可能是预测失误的)长耗时、低优先级的请求已经开始在GPU上运行了,如果我们的调度器没有“打断”它的能力(即非抢占式),那么后续到达的、即使是优先级非常高、对延迟要求非常苛刻的请求,也只能眼睁睁地看着宝贵的GPU资源被那个低优请求长时间占用,自己则在队列中苦苦等待。
- 3.1.2 抢占在LLM服务中的核心动机:
- 保障高优先级请求的服务等级目标 (SLO): 这是引入抢占机制最主要的驱动力。当一个带有严格SLO(例如,极低的TTFT要求)的高优先级请求到达,而系统当前资源(如空闲的GPU计算槽位或足够的连续显存)不足以立即满足它时,通过抢占一个或多个正在运行的、优先级较低的请求,可以迅速为其释放出所需的资源,确保其SLO得到满足。
- 应对突发的系统过载或SLO违约风险: 系统在运行过程中,可能会因为各种原因(例如,流量洪峰、对某些请求资源消耗的预估不足、某个GPU实例性能下降等)突然进入过载状态,或者监控系统检测到某些正在运行的请求即将导致自身或其他关联请求的SLO发生违约。在这种紧急情况下,抢占式调度可以作为一种“熔断”或“纠偏”机制,主动中断一些低优先级或“行为不良”(如远超预期长度)的请求,以缓解系统压力,保护核心服务的SLO。
- 你的论文明确指出了抢占的必要性: “为了保障高优先级请求的SLO或应对突发的系统过载,抢占式调度(Preemptive Scheduling)成为一种必要的机制”【cite: 35】。
- 并且进一步阐述了其运作方式:“当更高优先级的请求到达,或者系统检测到某些正在运行的请求可能导致SLO违约时,调度器可以主动中断(抢占)一个或多个当前正在运行的低优先级或长耗时请求,将其资源释放出来,以满足更紧迫的需求”【cite: 35】。
3.2 抢占的实现方式与挑战
说起来容易,但要在一个LLM服务系统中真正实现高效且可靠的抢占,并非易事。
- 3.2.1 核心挑战:请求状态(尤其是KV缓存)的管理
- 抢占一个LLM推理请求,远比简单地“杀死”一个无状态的Web服务进程要复杂得多。因为LLM请求是有状态的,其核心状态就是我们反复强调的KV缓存。
- 如果一个正在运行的LLM请求被抢占,为了能够在未来某个时刻从它被中断的地方恢复执行(而不是从头开始,那样会浪费掉之前所有的计算),系统必须能够可靠地保存它被抢占时的完整KV缓存状态。
- 巨大的开销: 保存一个可能达到数GB甚至数十GB的KV缓存(通常需要从GPU显存拷贝到CPU主存,在极端情况下甚至可能到磁盘),以及后续在恢复执行时再将其加载回GPU显存,这个过程会消耗大量的时间和I/O带宽。这个抢占和恢复的开销必须被仔细评估。如果抢占带来的好处(比如为高优请求节省的等待时间)还抵不上抢占本身的开销,那么抢占就得不偿失了。
- 3.2.2 论文中提及的类抢占机制实例:
- Llumnix系统的间接抢占(通过请求迁移):
- 你的论文提到:“Llumnix Sun et al. (2024)虽然不直接称其为抢占,但其通过将高优先级请求周围的其他请求迁移走,实际上为高优请求动态地“清理”出一个低干扰的执行环境,达到了类似抢占的效果”【cite: 36】。也就是说,Llumnix通过主动“挪走”低优请求,来为高优请求“腾地方”,这在效果上与直接抢占低优请求是相似的。
- 并且,“其本身的动态重调度能力也隐含了对导致拥塞或性能下降的请求的“驱逐”能力”【cite: 36】。
- FastServe系统的时间分片(论文提及,但引用需注意):
- 论文中还提到:“FastServe (引用缺失, 原文为Abhyankar et al. (2024), 但ref17是InferCept) 则明确采用抢占式的时间分片方法来优化请求的完成时间”【cite: 36】。虽然这里的具体文献引用在原论文中标注为可能有误,但它提示我们,基于时间片轮转的抢占也是一种可行的思路,即每个请求只允许连续运行一个固定的时间片,时间到了就必须让出资源,这天然地实现了抢占。
- QLM系统的请求驱逐机制:
- 这是一个更直接的抢占例子。论文介绍:“QLM 系统 Agrawal et al. (2024)支持请求驱逐机制:当其RWT (Request Waiting Time)估计器检测到潜在的SLO违规时,全局调度器可以将一个正在运行的请求组从GPU的运行批次中移出,放回等待队列,以便为更紧急的请求组腾出空间”【cite: 37】。这里的“驱逐”就是一种抢占行为,它将正在运行的请求(组)暂停,并将其状态保存(可能放回等待队列,意味着KV缓存需要被处理),以便为更高优先级的请求服务。
- Llumnix系统的间接抢占(通过请求迁移):
3.3 公平性保障 (Fairness Assurance)
抢占机制在追求效率和响应性的同时,也带来了一个非常棘手的副作用——不公平,甚至可能导致某些请求永远无法完成。
- 3.3.1 “饿死” (Starvation) 问题:
- 抢占的本质是优先满足一部分请求(通常是高优先级)的需求,代价是牺牲另一部分请求(通常是低优先级)的即时执行权。
- 如果系统中高优先级的请求持续不断地到达,那么低优先级的请求就可能被反复抢占,或者一直处于等待队列的末尾而得不到调度,最终导致它们长时间得不到服务,甚至永远也无法完成。这种现象,我们形象地称之为“饿死”。
- 你的论文敏锐地指出了这一点:“在多租户环境中,公平性是与效率同等重要的考量因素。抢占虽然能保证高优请求,但也可能导致低优请求长时间得不到服务(即“饿死”)”【cite: 38】。
- 3.3.2 在抢占与公平之间寻求平衡:
- 因此,一个成熟的调度系统,在引入抢占机制的同时,必须辅以相应的公平性保障措施。不能为了极致的优先级而牺牲掉所有低优先级任务的生存权。
- 3.3.3 借鉴差额轮询 (Deficit Round Robin - DRR) 的思想来保障公平性:
- 如何在保障优先性的同时兼顾公平性呢?你的论文介绍了一种借鉴自传统网络流量调度领域的经典思想——差额轮询 (DRR) ——的尝试。
- 论文提到:“因此,调度策略需要在抢占的果断性和系统的整体公平性之间取得平衡。Cao等人提出的DLPM (Deficit Longest Prefix Match)和D2LPM算法 Cao et al. (2025),借鉴了传统网络调度中的差额轮询(Deficit Round Robin, DRR)思想,通过为每个客户端/任务维护一个“差额计数器”来控制其资源获取,旨在保证公平性的同时,尽可能利用LLM对话中常见的前缀缓存局部性(prefix locality)来提高效率”【cite: 38】。这里Cao等人2025年的工作是论文参考文献中的[14](对应我们上下文的源[98])。
- DRR及其变种的核心思想(通用解释):
- 系统会为每个服务队列(或每个客户端/任务)分配一个名义上的“服务配额”或“信用点数”(quantum)。
- 在每一轮调度中,如果一个队列使用了少于其配额的服务量,那么它未用完的“差额”(deficit)会被累积到下一轮,使其在下一轮有机会获得更多的服务。
- 如果一个队列的请求超过了其当前配额(包括累积的差额),那么多余的请求就需要等待。
- 这样,即使是低优先级的队列,只要它持续有请求,它的“差额”就会不断累积,最终总能累积到足够的“信用”来获得服务机会,从而避免了绝对的饿死。
- 这些基于DRR思想的算法,试图在LLM服务中实现一种加权公平 (weighted fairness) 或 有界不公平 (bounded unfairness),而不是简单的“赢家通吃”的绝对优先级。
3.4 抢占决策的复杂性
即使有了抢占机制和一定的公平性保障,调度器在实际执行抢占时,仍然需要做出很多复杂的决策。
- 3.4.1 何时触发抢占 (When to Preempt)?
- 是仅在高优先级请求到达且无空闲资源时才抢占?还是在系统负载达到某个阈值,或某个关键SLO(如P99延迟)即将被违反的“事前”就主动进行预防性抢占?这些触发条件的设定,直接影响抢占的频率和效果。
- 3.4.2 应该抢占谁 (Whom to Preempt)?
- 如果有多个正在运行的、可被抢占的低优先级任务,调度器应该选择哪一个或哪几个来抢占呢?
- 选择的标准可能包括:
- 优先级最低的?
- 已经运行时间最长的(或最短的)?
- 抢占代价最小的? (例如,其KV缓存最小,或者保存/恢复速度最快)
- 对系统整体目标贡献最小的? (例如,一个预计对提高整体吞吐量帮助不大的请求)
- 取得进展最少的?
- 3.4.3 如何执行抢占 (How to Preempt)?
- 是将被抢占的请求彻底中止(后续需要从头开始),还是仅仅暂停并保存其完整状态以待后续恢复?对于LLM这种有状态的计算,后者通常是更可取的,但也更复杂。
- 抢占的粒度是什么?是抢占整个GPU上正在运行的一个批次,还是能够更细致地抢占批次中的某一个或某几个特定请求?
- 3.4.4 对全局信息和智能的需求:
- 显然,要做出这些精细的抢占决策,调度器必须能够获取并综合分析关于当前系统全局状态(如各GPU的负载、可用显存、排队情况)、所有请求的特征(如优先级、已处理长度、预测剩余长度、SLO要求)、抢占和恢复的预估开销、以及长期公平性目标等多方面的信息。这再次凸显了LLM调度需要高度的“智能性”。
总结与过渡 (2-3分钟):
- 回顾: 同学们,今天我们深入探讨了“抢占式调度”这一在LLM服务中用于保障高优请求SLO和应对系统过载的强力手段。我们理解了其核心在于对LLM请求状态(主要是KV缓存)的有效管理(保存与恢复),并认识到它虽然威力巨大,但也必须辅以如DRR等机制来解决其可能带来的“公平性”问题(如低优请求饿死)。我们还分析了抢占决策本身的复杂性。
- 核心权衡: 抢占式调度体现了在“极致响应”与“系统公平和整体效率”之间的一种动态权衡。
- 展望: 到目前为止,我们已经学习了基于预测的调度(优化执行顺序)和抢占式调度(主动中断执行)。这些都是调度器自身如何变得更“聪明”的体现。那么,这些调度决策如何与更高层级的资源管理策略,比如根据负载动态调整GPU实例数量的“自动伸缩”机制,进行有效的协同呢?这就引出了我们接下来要简要探讨的、与本节(3.2节)相关的最后一个话题:面向自动伸缩的调度机制。
今天的第三部分内容就到这里。谢谢大家!