一家包装企业的产品知识库,同时提问的人一多就排队:8 个人一起问,最慢的那位要等 51.8 秒。客户的想法很直接:大模型的 Key 已经备了十一把,再加点内存、加几个核,是不是就能撑三十个人同时用?
这个问题我们在生产机上一样一样实测过。结论是:Key 和内存一个名额都加不出来,请求根本没排在客户以为的地方;核只在 8 个以内管用,再往上就不划算了。真正卡住的,是我们自己给资料打分排序的那一步。
请求还没走到模型那边
先测 Key。单独一把 Key,48 路并发同时打过去,全部成功,一路都没被限流,每秒能处理 10.6 次。再看整台机器:即便后来我们把自己这边优化完,每秒也只能答 0.4 次左右,只有一把 Key 扛得住的二十几分之一。一把的余量都用不完,多出来的那十把,对速度没有任何帮助。
请求还没走到模型,就先在我们自己的重排上排起了队。重排是检索里的一步:前面先捞出一批候选资料,重排再给每条候选打分,挑出最相关的几条交给大模型。一个问题的计算量几乎全压在这一步,检索里其余几步(把问题转成向量、查向量库)实测耗时接近于零。
内存也一样。压测时 CPU 一直满载,内存一直有余量,优化完之后峰值也不到上限的一半。CPU 早就满了,内存加再多也换不来一个名额。
核只到 8 个为止管用
加核要分两段看:4 核到 8 核,吞吐翻了一倍多;8 核到 11 核,核多了 38%,吞吐只多 13%。
原因还在重排。它原来是 8 条资料一批一起算,实测既慢,又会把排名算错:24 组测试,没有一组排对。改成逐条算,速度是原来的 1.67 倍,结果也对了,但各个核之间互相等待的时间变多,曲线到 8 核就弯了。
改造只动我们自己这边,一共三件事:早先为压内存峰值加过一把全局锁,它把整条检索排成了单行道,我们把它收窄,不再锁住整条检索,只在重排这一步加一道限制同时并发数的闸;重排改成逐条算;检索服务可用的核放到 8 个。每秒能答的问题从 0.15 次提到 0.4 次左右,按每人两分钟问一次算,同时在线从 17 人到 44~52 人(约 48 人)。三件事里,没有一件是加 Key 或加内存。
我们现在的规矩
- 客户问容量,只拿实测回答。 不实测就建议加钱,结果是钱花了,容量不变。
- 多备 Key,用处是容错。 一把坏了,自动换下一把。同一个账户下的 Key 共用一份余额,钱用完了换哪把都一样,系统直接整组暂停使用,不挨个白试。
- 过了 8 核,扩容靠加机器。 检索请求彼此独立,把资料库整份复制到新机器、入库时两台一起写,前面加一层分流就能加机器。按实测曲线推算,一台 16 核只比 8 核多三成吞吐,两台 8 核能翻一倍,同样的钱收益差三倍。
- 计算方式一改,旧结论必须重测。 成批算的时候,8 核到 11 核还是线性的;换成逐条算,这条就不成立了。拿旧曲线去定机器配置,就会买错。
- 排队只报「前面还有 N 位」。 预计秒数估不准:同样是「前面还有 6 位」,两次实测一次等了 19.8 秒,一次等了 51.2 秒,我们两次估的都偏短。报短比不报更伤信任。只报位置,句句是事实,数字一路往下掉——9、7、6、5、4、2,然后「正在检索」——本身就说明没卡死。
- 实测要防三个假象。 一是缓存命中冒充性能:检索有缓存,拿同一批问题反复压测,测到的只是缓存的速度,所以压测只用没问过的问题。二是单次采样当结论:同样一次检索,快的 3.7 秒,慢的 7.0 秒,至少 16 个样本才算数。三是把大模型写字的时间算进来:一个长答案能写到一万六千个字符,写字的时间比检索长得多,却不在我们这边排队,混在一起测,检索这一段的容量就被盖住了。测容量只测检索这一段。
扩容的钱,要花在请求真正排队的地方。
