日期:2026-08-27
我们的向量库跑了大半年,增删改一直往上堆,没人盯着索引健康。某天检索召回率莫名其妙掉了,排查半天才发现是早期一批脏数据混进了索引,还有几段文档删了但向量没清干净。更难受的是,谁也说不清当前索引和源文档到底一不一致,想重建索引又怕停服影响线上检索,只能硬扛。那段时间,客服那边的"搜不到"工单悄悄多起来,我们却找不到原因。
最尴尬的一次,是市场部用我们的检索做竞品分析,结果漏掉了一半相关文档,得出的结论差点误导了一次定价会。事后复盘,根因就是索引悄悄劣化没人管。这件事让我们意识到,向量库不是建完就完事,它和数据库一样会"脏",得有日常对账和体检的机制,否则问题是会积累着爆发的。
我们给向量库加了健康度监控,定期扫索引的碎片率、脏条目数和召回抽检命中率。重建不再是一刀切停服,而是编排成增量重建和分片轮换:先把新索引在备库建好,再分片切流量过去,单分片重建期间该分片走只读降级。源文档和向量之间做了周期性一致性校验,发现对不上的条目自动标记修复。整套流程跑下来,重建这件事从"不敢动"变成了"定期例行",运维排期表里多了一项周检,再没人怕动索引。
为了把影响压到最低,我们还做了重建期间的流量染色,被重建的分片请求打标后走降级链路,返回略旧的缓存结果,用户基本无感。校验结果也接到了看板,碎片率一黄就有人看。
重建停服是最早的拦路虎。第一次全量重建我们直接锁了写半小时,线上检索一半请求超时,被业务方追着问。后来改成按分片轮换,每次只重建一个分片、切一小撮流量,写操作在其他分片照常,影响降到几乎无感。一致性校验也不简单,源文档和向量的映射要靠稳定主键,早期主键设计乱,对不上只能靠内容指纹兜底,慢且不准。我们重做了主键规范,校验从天级降到小时级。
脏数据修复要谨慎,标记错的条目直接删会误伤,我们改成先隔离观察再清,留了回滚窗口。还有一个隐蔽坑:增量重建时源文档正在被删,新索引可能漏掉删除事件,我们给重建任务加了删除日志回放,确保删操作不丢。
案例片段(已脱敏): 索引健康度与一致性校验的核心配置如下:
yaml index_health: fragment_alert: 0.15 # 碎片率超15%预警 recall_sample: 200 # 每日抽检200条召回 rebuild: mode: shard_rotation # 分片轮换,不停服 shard_batch: 1 consistency: check_interval: 1h isolate_before_delete: true一次巡检发现某分片碎片率达 28%,轮换重建后召回抽检命中率回升到 99.1%,全程线上零超时。
重建之前我们养成了先打快照的习惯,万一轮换途中发现新索引有问题,能在一分钟内回滚到旧索引,这个演练我们每月跑一次。早期有人嫌麻烦跳过,结果一次备库磁盘满导致重建失败,幸亏有快照才没影响线上。从此快照成了硬性前置步骤,写进运维手册第一条。备份这种事,平时觉得多余,出事一次就明白是救命绳。
召回率波动从之前肉眼可见的下滑,收敛到稳定在九成九以上,再没出现过"检索突然变傻"的投诉。重建耗时从锁写半小时,变成按分片轮换、单分片分钟级,线上零感知。不一致条目从最多时上千条,压到常态化个位数,且能在小时内被发现。查询降级率在大促期间也维持在千分之一以内,用户基本无感。那次误导定价会的风险,之后再没出现过,市场部现在敢直接拿我们的检索结果做分析。
向量索引是会悄悄劣化的,别等召回率掉了才想起来查,健康度监控要当成标配,碎片率和抽检命中率这两个指标最直观。重建一定要走增量或分片轮换,全量锁写是给业务方递刀子,我们吃过那次亏之后再没敢这么干。一致性校验的前提是主键规范,源和向量的映射乱了,再聪明的算法也救不回来,重做主键虽然痛,但值得。脏数据修复留隔离窗口,宁可慢一步删,也别误伤正常条目。说白了,向量库的运维和数据库一样,得有"对账"的思维,不能建完就当甩手掌柜,定期体检比事后救火省心得多。
从成本视角看,定期重建顺带清理了长期占着的脏向量,索引体积缩了将近三成,存储和查询开销都降了。我们一度以为重建只是为召回率,后来发现它顺手把库存也整理了,这种意外收益,是运维常态化才有的。
我们把这套健康度看板接到了告警群,碎片率一黄就有人看,从被动救火变成了主动体检。很多稳定性问题,缺的不是技术,而是一个能让人一眼看见异常的信号,信号有了,人自然就动起来了。