系统日活从 100 涨到 10 万,架构要变什么?

Q8-10场景设计 · 扩展性追问常见场景设计容量规划goodputKV-Cache长尾兜底策略压力追问

谁在问:三面 / 架构向;常与成本追问成对出现,考的是你有没有在真实规模上待过

口语化问法

  • 这套东西现在只有一百个人在用,涨到十万日活,哪儿会先崩?
  • 用户量翻一千倍,你的架构要改什么?
  • 大促当天流量再翻五倍,你怎么扛?

考察意图

这道题的第一个陷阱在题面里:「日活」不是容量单位。日活 10 万可能意味着峰值并发 50,也可能意味着 5000,取决于使用形态。上来就开始扩容的人,第一步就错了。

其余三层:

  1. 你知不知道各层的拐点不同。检索侧、生成侧、数据侧在完全不同的量级上出问题,一起扩是浪费。
  2. 你会不会做容量规划。峰值吞吐是宣传数字,真正能用于规划的是有效吞吐
  3. 你知不知道一千倍不是线性放大。有些东西会变好(缓存命中率),有些会变差(长尾变长、评测集失效),有些会直接失效(人工兜底)。

参考答案

图 2 · 60 分与 90 分差在哪:代价、演进、怎么验证

60

60 分答案(及格线)

先做水平扩展,检索服务和应用服务加机器、加负载均衡;向量库要考虑分片;模型调用侧要加限流和排队,避免打爆上游;再加缓存降低重复请求。监控要跟上,看各层的延迟和错误率。数据库读写分离,热点数据加 Redis。

这是通用的 Web 扩容答案,及格但不切题。它没有回答任何和大模型应用相关的特殊性——生成侧的容量约束、长上下文对并发的影响、缓存结构的变化、以及兜底策略的失效。

90

90 分答案(有生产经验的回答)

① 先澄清:涨的到底是什么。 日活 10 万要先换算成峰值并发每秒请求数——同样是 10 万日活,一天用一次的工具和坐席全天在线的客服,并发差两个数量级。还要问:长上下文请求的占比是多少(这直接决定生成侧的容量),以及数据量是不是同步涨了(用户涨不一定文档涨,两者的扩容路径完全不同)。

② 回到基线:先找当前架构的第一个拐点在哪。 不要三层一起扩。做法是压测,看哪一层先崩。经验上顺序通常是:生成侧 → 检索侧 → 数据侧,因为生成侧的单位成本和资源占用远高于其他两层。

③ 分层说变什么、代价是什么

  • 生成侧(最先出问题的一层)。如果走 API,主要工作是限流、排队、优雅降级和多供应商冗余;如果自建,核心约束是显存:KV Cache 吃掉的显存决定了能同时挂多少条会话,容量限并发、带宽限单步。这里有一个必须说清的效应:上下文越长,并发掉得越快——同一张卡在 8K 上下文下能挂几十条并发,到 128K 可能只剩个位数。所以「支持超长上下文」在规模化之后是一个容量决策,不是一个功能开关。
  • 容量规划只能用有效吞吐。峰值吞吐是「不管延迟多难看,一秒能吐多少 token」,而真实业务有延迟约束,满足延迟要求的那部分吞吐才能用于规划。用峰值吞吐做容量规划,上线当天就会发现算少了一半。
  • 检索侧:向量索引到一定规模要分片,且召回质量会随库变大而下降——同样的 top-k 在百万级库里的噪声比十万级大得多,所以扩容的同时通常要提高召回数并加强重排。代价:延迟和成本都上升。还要注意增量更新的压力:数据量涨了之后,重建索引从「凌晨跑一次」变成不可行,必须做真正的增量。
  • 数据侧:更新频率、一致性、以及权限判定的 QPS(toB 场景里这一项经常被漏,每次检索都要查一遍权限)。
  • 缓存结构会变好:用户涨一千倍之后,问题分布会更集中,精确缓存和前缀缓存的命中率通常显著上升——这是规模带来的红利,应该主动去吃。但语义缓存的风险同时放大,因为误命中的绝对次数随请求量线性增长。
  • 长尾会变长:100 个用户时你见过的问题类型是有限的,10 万用户会把长尾拉得很长。这意味着评测集会失效——原来的一百条评测题不再代表线上分布,必须按新的真实分布重采。这条最容易被漏,但它是「上线后效果变差」的常见原因之一。
  • 兜底策略会直接失效:100 日活时「不确定就转人工」完全可行,10 万日活时人工兜底会被淹没。所以扩容不只是扩机器,是要重新设计兜底——把一部分兜底从人工换成自助(引导到帮助中心、给相似问答、给结构化表单)。

④ 怎么验证扩对了:压测要用真实分布的流量回放而不是均匀请求,因为长上下文请求的资源占用完全不同;监控要分桶看(按请求类型、按上下文长度分桶),总均值会掩盖问题;同时要盯有效吞吐和排队时长,而不只是 QPS 和成功率。

⑤ 什么时候该做下一步:出现「峰值时排队时长超过用户耐心」→ 扩容或降级;出现「长尾问题占比持续上升且转人工被打满」→ 该扩知识覆盖和自助兜底,不是扩机器;出现「同一类请求每天几万次且稳定」→ 才考虑蒸馏小模型或专用路由。退路:任何一次扩容后效果指标下降,先回滚再排查——规模问题最容易和质量问题混在一起,不隔离就查不清。

追问链

图 1 · 五层追问树:面试官会往哪儿挖
第一个坑在题面里:日活不是容量单位,一千倍也不是线性放大

  1. 你会先扩哪一层?怎么判断?

    期望不猜,压测:① 真实分布的流量回放逐层加压,看谁先崩;② 经验顺序是生成侧最先,但必须验证不能假设 —— 库特别大或权限判定特别重时顺序会变;③ 判据不是「谁的 CPU 先满」,是谁先突破延迟约束;④ 扩之前先找便宜办法:缓存命中率、重复请求、有没有一类请求本来就不该走完整链路
    信号说得出「用真实分布回放而不是均匀压测」→ 压过真实系统;直接给扩容顺序不谈验证 → 背的经验
  2. 为什么长上下文场景并发掉得那么快?

    期望KV Cache 随上下文线性吃显存,而显存固定。① 单条占用看长度、层数、KV 头数(不是注意力头数,分组查询注意力下差很多)、精度;② 总显存 ÷ 单条占用 = 并发上限,容量限并发;③ 每步解码重读 KV Cache,带宽限单步。同卡 8K 挂几十条,128K 只剩个位数
    信号用 KV 头数而不是注意力头数算 → 学过真东西;点出「memory-bound 是关于 batch size 的陈述」→ 理解到位
  3. 峰值怎么算容量?按供应商标称的吞吐吗?

    期望不能。① 标称峰值在无延迟约束下测得,真实业务有首字与逐字延迟约束,只有满足延迟约束的那部分吞吐可用于规划;② 按有效吞吐算并按请求类型分桶,长上下文与短请求不能混一个数;③ 留余量给排队:到达不均匀,按平均值规划会在峰值全线排队;④ 自建再算预热、模型加载、故障时的容量重分布
    信号明确说「峰值吞吐不能用于容量规划」→ 做过容量规划;拿标称数字乘个系数 → 没上过量
  4. 用户涨一千倍,缓存命中率会怎么变?

    期望通常变好,但要分层看:① 精确与前缀缓存命中率上升:用户越多问题分布越集中,是规模红利 —— 把系统提示和工具定义固定死去吃它;② 语义缓存绝对风险同步放大,误命中次数随请求量线性涨,责任在你;③ 反向效应是长尾变长,尾部命中率反更低,总命中率上升会掩盖尾部变差 —— 必须分桶看
    信号说得出「总命中率上升可能掩盖尾部变差」→ 看过真实的分桶数据;只说「缓存会更有用」→ 答对一半
  5. 大促当天流量再翻五倍,上游还限流了,你怎么降级?

    期望从不影响正确性到影响功能排:① 削非关键路径(解释性输出、相关推荐、可选二次校验,安全类保留)→ ② 降召回数、重排数、effort 档位、最大轮次 → ③ 走缓存与预置答案(权限场景必须分桶)→ ④ 按用户与请求分级排队,等待可见 → ⑤ 减功能:关长尾入口、不可逆操作转人工。上游专项:多供应商冗余、快速失败、退避抖动、幂等;恢复条件事先约定、能一键回滚
    信号给得出「从不影响正确性到影响功能」的降级链并提退避抖动与幂等 → 真值过大促;只说「加机器 + 限流」→ 没有优先级概念
只会「加机器、加分片、上 Redis」的,第 1 层就露馅 —— 前三层验容量单位与有效吞吐,第 4、5 层才是分水岭:规模红利与长尾变差同时发生时,你的降级链有没有优先级。

评分要点

  1. 先把日活换算成峰值并发,并问长上下文请求占比
  2. 不三层齐扩,压测找第一个拐点
  3. 生成侧讲清 KV Cache 三层账(容量限并发、带宽限单步)
  4. 容量规划用有效吞吐而非峰值吞吐,且按请求类型分桶
  5. 检索侧知道库变大召回质量下降,要提召回数并加强重排
  6. 知道规模带来缓存红利,但语义缓存风险同步放大
  7. 知道长尾变长会让评测集失效,必须按新分布重采
  8. 知道人工兜底会在规模化后失效,兜底策略要重新设计
  9. 降级给出有优先级的链条,含退避抖动与幂等

常见错误

直接给通用 Web 扩容方案没有回答大模型应用的特殊性
不把日活换算成并发容量单位就搞错了,后面全是空谈
三层一起扩浪费,且找不到真正的瓶颈
用标称峰值吞吐做容量规划上线当天就会发现算少一半
用注意力头数算 KV Cache分组查询注意力下会算错很多
「解码是访存瓶颈」当本质属性那是关于批大小的陈述
完全不提评测集失效会把「分布变了」误判成「模型变差了」
兜底策略照搬小规模的做法人工兜底在十万日活时会被淹没
降级只有「限流」一招没有优先级,体验和功能一起崩

关联学习