记录一下部署vLLM过程中踩到的坑
1. 部署一个vLLM服务 前一段手上拿到一批昇腾 910C,考虑到可以给大家部署一些vLLM服务来用,本来以为就是按照vLLM的官方教程一步一步走完就行了,事实上也确实是这样的,一步一步走完了流程,但是能用和好用确实是两回事情,后面为了vLLM好用踩了不少坑。 先说一下我们用到的模型的情况,经过对kimi-k3、glm-5.2、glm-5.3-flash、deepseek-v4-flash、deepseek-vision等多个模型的测试,在推理性能、占用资源数、模型能力之间取了一个平衡,最终选择部署deepseek-v4.1-flash(dsv4.1-flash),上下文选择了一个比较适中的范围:600k,同时开启了dspark加速。 2. 多实例负载均衡 最先遇到的问题是单实例服务能力不够,最直接的想法就是搞多实例然后在new-api层做负载均衡,单手后期运维起来由于new-api没有做联动,有点运维难度,且负载均衡导致缓存命中降低,所以选择在vLLM和new-api之间加了一层router来做负载均衡。 最早的router是配置文件形态:引擎列表写死在配置里,加减引擎要改配置、重载。引擎少的时候忍忍也就过去了。 后来换了新一代动态router:引擎主动注册,自带cache-aware调度(前缀亲和,同一前缀尽量打到同一引擎)、失败重试、熔断摘除。和看门狗配合之后形成两层防御: 看门狗管"引擎挂死":真实推理探针,连续失败整组重启; Router 管"坏引擎别接流量":探活失败摘出路由,恢复后自动回归。 3. KV缓存问题 影响vLLM的服务质量TTFT的最大因素就是KV缓存,由于我想部署多个实例,导致留给KV的空间就剩下很少了,所以就需要考虑把KV卸载到DRAM或者SSD上,最开始用到的就是MemCache来做KV缓存管理。共享缓存的第一步是 MemCache:vllm-ascend的AscendStoreConnector,在本机内存里开一块池,把前缀 KV 存出去,下一个请求来了先查池。 但是在实际上线服务的时候遇到很多奇怪的问题: 存的日志一切正常,块块都写进去了; 审计计数器显示查询也在跑,exist请求源源不断,还能查到一部分key; 但命中恒为 0,TTFT 纹丝不动。 当时给它起了个名字叫"只存不取",一度怀疑池子根本没接上。真正的转机是把日志开到DEBUG重启,再加一个受控探针:灌入约50k的前缀token → 用流量把池驱逐干净 → 原样重发。 池侧逐组核对,exists全中:96/96、5/386……每个key都在; 紧接着一行 final hit=0; 请求全量冷预填。 所以不是"只存不取",是查到了也算零命中。卡点在"查到之后怎么算命中长度"。 对着源码读才发现是粒度基不一致:池里存的是32-token粒度的块哈希,而vLLM core的契约写得明明白白——查命中时调用方必须传"对齐粒度 = 哈希粒度"(源码注释原话:caller passes alignment_tokens = hash_block_size)。我们部署分支的协调器传的却是引擎块大小128。128对32,取出来的哈希和池里存的根本不是同一批值,第一块就miss,后面全部作废。 先试了一行补丁:把128改成32,第一组立刻命中12288——成功了一组。但滑窗组不支持细粒度命中(直接断言),压缩器状态组的粒度又不一样,池侧还有一层按错误粒度截断的覆盖上限。修到最后确认:这个分支(vLLM 0.23)的命中路径就是个半成品,补丁救不完。 真正的解法是上游 v0.30.0rc1 把这条路径正面重写了:查询集收窄到"可前缀缓存的组",统一调度侧和 worker 侧的命中语义。换镜像,命中日志直接出现,一行补丁都没打。顺手还赚了个惊喜:新版本把查找表挪到了主机内存,腾出来的显存全给了KV池——池容量6.88倍(98万 → 678万token),600K长文加16并发在容量上从此无障碍。 4. 共享KV池 MemCache修好之后,后续的问题也逐渐暴露出来了:池是"每节点一份"的孤立池(元服务绑在本机回环地址上),跨节点从来没有真正通过;引擎一重启,池就空。用户的文档就那几份,却要每个引擎各存一份、重启全丢、再各预填一遍。 4.1 MemCache方案 把各节点的元服务指到同一个中心点:段注册、挂载、全局rank偏移,所有前置步骤全绿。然后跨节点put,100%失败(error -1),重试的put风暴反手把引擎拖死。关掉fabric内存直传的开关复测,依旧。 4.2 Mooncake方案 换分布式KV store:master起来了、几十个段全部挂载成功、对端引擎也能连上——万事俱备。然后put计数恒为 0,设备侧内存拷贝全部超时(EE1002)。想退回普通TCP传输:vllm-ascend硬编码只认昇腾直连协议,NotImplementedError,此路不通。 4.3 问题定位 上述两个方案都是经过单实例验证过的,但是最后都卡死在KV传输上,可奇怪的是这批节点正常训练都NPU传输数据是完全没问题的,凭什么 KV 不行? ...