跳转至

LLM推理服务架构设计

面试频率:字节/阿里/百度AI Infra方向必考题 核心考点:高并发、低延迟、成本优化的LLM推理系统


1. LLM推理的特殊性

与传统模型推理(BERT/ResNet毫秒级)不同,LLM推理有独特挑战:

特性 传统模型推理 LLM推理
延迟 1-50ms 2-30s
模式 单次前向传播 自回归逐Token生成
显存 GB级 十GB到百GB
输出 固定大小 变长(几个Token到几千Token)
批处理 固定Batch 动态Batch(请求到达时间/长度各异)

2. 完整推理服务架构

Text Only
┌─────────────────── 接入层 ───────────────────┐
│ 客户端 → CDN(静态) → LB(Nginx/ALB)           │
│ → API Gateway:                                │
│   - 认证/鉴权(API Key + Rate Limit)           │
│   - 请求验证(Token长度/内容安全)               │
│   - 路由策略(模型选择/区域)                    │
└──────────────────┬──────────────────────────┘
┌─────────────────── 调度层 ───────────────────┐
│ 请求队列(Redis Stream / Kafka):               │
│   - 优先级队列(VIP用户/普通用户)              │
│   - 长度分桶(短请求→快队列, 长请求→慢队列)    │
│   - 背压控制(队列满时拒绝/降级)               │
│                                               │
│ 智能路由器:                                    │
│   - 简单Query → 7B模型(高并发池)              │
│   - 复杂推理 → 70B模型(高质量池)              │
│   - 代码生成 → 代码专用模型                    │
│   - 多模态   → VLM模型池                      │
└──────────────────┬──────────────────────────┘
┌─────────────────── 推理层 ───────────────────┐
│ vLLM / TensorRT-LLM / SGLang 集群:           │
│                                               │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐      │
│ │ 7B Pool  │ │ 70B Pool │ │ VLM Pool │      │
│ │ 16×A10G  │ │ 8×A100   │ │ 4×A100   │      │
│ │ INT4量化 │ │ FP8量化  │ │ FP16     │      │
│ │ 并发200+ │ │ 并发40   │ │ 并发20   │      │
│ └──────────┘ └──────────┘ └──────────┘      │
│                                               │
│ 关键优化:                                     │
│   - PagedAttention(显存碎片化解决)             │
│   - Continuous Batching(动态批处理)           │
│   - Prefix Caching(系统Prompt缓存)            │
│   - Speculative Decoding(投机解码加速)         │
└──────────────────┬──────────────────────────┘
┌─────────────────── 输出层 ───────────────────┐
│ SSE流式响应 → 安全过滤 → Token计量 → 客户端   │
└──────────────────────────────────────────────┘

┌─────────────────── 运维层 ───────────────────┐
│ 监控: Prometheus(QPS/延迟/GPU利用率) + Grafana │
│ 扩缩: K8s HPA(基于GPU利用率+队列长度)         │
│ 模型: 热加载/灰度发布/A/B测试                  │
└──────────────────────────────────────────────┘

3. 核心优化技术(面试必考)

3.1 PagedAttention

传统KV Cache:为每个请求预分配最大长度的连续显存 → 严重浪费

Text Only
传统方案(预分配):
  请求A(实际200 Token, 预分配2048): [████░░░░░░░░░░░░░░░░] 90%浪费
  请求B(实际500 Token, 预分配2048): [██████████░░░░░░░░░░] 75%浪费
  → 显存利用率低,并发数受限

PagedAttention(按需分页):
  请求A: [Page1][Page2][Page3]...(按需分配,用完释放)
  请求B: [Page1][Page2][Page3][Page4][Page5]...
  → 显存利用率从30%→90%,并发提升2-4倍

3.2 Continuous Batching

传统Static Batching:一个Batch内所有请求等最长的完成才能释放

Text Only
Static Batching:
  时间 →  ────────────────────────────→
  请求A:  [████████████████████████████]  (长请求)
  请求B:  [████████]                      (短请求,但等A完成才释放)
  请求C:  [████████████]                  (中请求,同上)
  → 短请求延迟被长请求拖累,GPU利用率低

Continuous Batching:
  时间 →  ────────────────────────────→
  请求A:  [████████████████████████████]
  请求B:  [████████]→释放→[请求D填入]
  请求C:  [████████████]→释放→[请求E填入]
  → 空出的位置立即被新请求填入,GPU始终满载

3.3 KV Cache量化与压缩

Text Only
KV Cache显存占用公式:
  KV_size = 2 × num_layers × num_heads × head_dim × seq_len × batch_size × precision_bytes

  7B模型, 32层, 32头, 128维, 4096 seq_len, batch=100:
  FP16: 2 × 32 × 32 × 128 × 4096 × 100 × 2B ≈ 214GB  ← 远超单卡显存!

优化:
  1. KV Cache FP8量化: 显存减半,精度损失极小
  2. GQA(Grouped Query Attention): KV头数远少于Q头数(如8 KV对32 Q)
  3. 滑动窗口注意力: 限制KV长度(如4096),超出部分丢弃/汇总
  4. Prefix Caching: 相同System Prompt的KV Cache复用

3.4 投机解码(Speculative Decoding)

Text Only
标准自回归: 大模型逐Token生成,每步都走完整前向传播
  Token 1 → Token 2 → Token 3 → ... → Token N
  延迟 = N × 大模型单步延迟

投机解码:
  小模型(1B)快速草拟K个Token → 大模型(70B)并行验证K个Token
  → 接受正确的前j个 → 从第j+1个重新生成

  加速原理: 大模型验证K个Token的成本 ≈ 生成1个Token(并行化)
  平均加速: 2-3倍(取决于小模型与大模型的一致率)

  适用: 大小模型能力差距大的场景(如70B做主模型, 1B做草稿模型)

4. 性能估算(面试必做)

题目:设计一个日调用1亿次的LLM推理服务,平均输入500 Token,输出200 Token。

Text Only
容量估算:
  日调用量:    1亿
  平均QPS:    1亿 / 86400 ≈ 1157 QPS
  峰值QPS:    1157 × 3 ≈ 3500 QPS

延迟目标:
  TTFT(首Token): < 1s (P99)
  TPS(生成速度): > 30 Token/s
  总延迟: TTFT + 200/30 ≈ 7.7s (P50)

GPU需求估算(以A100 80GB为例):
  单卡7B模型(INT4): 吞吐约500 Token/s(批处理)
  每请求200 Token输出 → 单卡约2.5 QPS(独占)
  但Continuous Batching下, 单卡可并发50+请求 → 有效QPS约50-80

  3500 QPS ÷ 60 QPS/卡 ≈ 60张A100
  + 冗余50%(故障/扩缩/排队) → 约90张A100
  + 如果用70B模型(单请求需4卡) → 需求量级更大

成本月估算:
  90 × A100云实例 × ¥40/小时 × 720小时 ≈ ¥260万/月
  优化:
    - 70%请求路由到7B模型(INT4, 成本1/10) → 节省50%+
    - Prefix Caching节省20% GPU时间
    - 低峰期缩容 → 节省30%
    → 优化后约¥80万/月

5. 面试高频追问

Q: 如何实现LLM推理服务的灰度发布?

Text Only
方案: 流量分桶 + 影子模式

  1. 影子模式(零风险验证):
     新模型部署后,接收与生产相同的请求
     但结果不返回给用户,只做日志对比
     → 对比新旧模型的质量/延迟/成本

  2. 灰度分流:
     5% → 10% → 30% → 100% 逐步放量
     关键指标(回答质量/延迟/用户反馈)任何一项恶化则自动回滚

  3. A/B测试:
     用固定的用户分桶(哈希用户ID)保证同一用户体验一致
     统计显著性达标后做决策

Q: 如何处理长尾请求(超长输入/输出)?

Text Only
  - 独立"慢车道"队列:长请求不阻塞短请求
  - 长请求使用流式分段生成
  - 超长输入(>128K)先做摘要压缩,再送入模型
  - 设置最大输出Token限制,超限截断并提示用户

Q: GPU机器挂了怎么办?

Text Only
  高可用设计:
  1. 健康检查: 每30s探测GPU状态 + 推理延迟
  2. 自动摘除: 异常实例从负载均衡器摘除
  3. 请求重试: 失败请求自动路由到健康实例(幂等性保证)
  4. K8s自愈: Pod失败自动重启/重新调度
  5. 多AZ部署: GPU实例分布在多个可用区

Q: 如何降低推理成本?

Text Only
  成本优化金字塔(从高到低效果):

  1. 模型路由(节省50-70%): 简单→小模型, 复杂→大模型
  2. 量化(节省50-75%): FP16→INT8→INT4, 质量损失评估
  3. KV Cache优化(节省20-30%): PagedAttention + Prefix Caching
  4. 批处理优化(节省20-40%): Continuous Batching最大化GPU利用率
  5. 弹性扩缩(节省20-30%): 低峰缩容, Spot实例混合
  6. Prompt压缩(节省10-20%): 压缩系统Prompt, 减少输入Token


最后更新:2026年2月