随着RAG(检索增强生成)和AI应用的普及,向量数据库成了很多团队的标配。我们团队也不例外,早在两年前就引入了向量数据库,用来做语义检索和知识库。

但随着数据量的增长和业务的发展,原来的向量数据库逐渐跟不上了。查询变慢、扩容困难、功能不够用,各种问题开始出现。于是,我们决定做一次向量数据库的选型和迁移。

这篇文章,就来分享这次向量数据库选型迁移的完整实战经历,包括需求分析、选型对比、迁移方案、踩过的坑和最终的效果。如果你也在考虑向量数据库的选型或者迁移,希望这篇文章能给你一些参考。

为什么要迁移

先说说为什么要迁移。

我们原来用的向量数据库,是一个比较轻量的开源方案。刚上线的时候,数据量只有几十万条,查询延迟在100毫秒以内,完全够用。

但两年下来,数据量增长到了几千万条,业务也从简单的语义检索,扩展到了多模态检索、推荐系统、实时分析等场景。原来的数据库开始出现各种问题:

第一个问题,查询性能下降。数据量超过一千万之后,查询延迟明显上升,从原来的100毫秒变成了500毫秒以上,高峰期甚至超过1秒。用户反馈搜索变慢了,体验很差。

第二个问题,扩容困难。原来的数据库是单机部署,扩容需要停机迁移,而且不支持水平扩展。数据量再增长下去,单机的磁盘和内存都扛不住了。

第三个问题,功能不够。原来的数据库只支持基本的向量相似度搜索,不支持标量过滤、混合查询、多租户、实时写入等高级功能。而我们的新业务,这些功能都需要。

第四个问题,运维成本高。原来的数据库社区不够活跃,文档不够完善,遇到问题很难找到解决方案。监控和备份工具也比较简陋,运维起来很费劲。

综合考虑之后,我们决定换一个更成熟、更强大的向量数据库。

需求分析

动手选型之前,我们先做了详细的需求分析。

功能需求:

  • 支持向量相似度搜索,包括余弦相似度、内积、欧氏距离
  • 支持标量过滤,能根据metadata过滤查询结果
  • 支持混合查询,向量搜索和关键词搜索结合
  • 支持实时写入和更新,数据写入后立即可查
  • 支持多租户,不同业务的数据隔离
  • 支持批量导入,方便历史数据迁移
  • 支持持久化和备份,数据不丢失

性能需求:

  • 数据量五千万条,向量维度1024维
  • 查询延迟P99在200毫秒以内
  • 支持每秒一万次查询的并发量
  • 写入吞吐量每秒一千条以上

运维需求:

  • 支持水平扩展,能在线扩容
  • 有完善的监控和告警
  • 有成熟的备份和恢复方案
  • 社区活跃,文档完善,有商业支持

成本需求:

  • 总体拥有成本可控,包括软件成本、硬件成本、运维成本
  • 最好是开源的,可以自主部署和定制

把这些需求整理清楚之后,我们就开始了选型。

选型对比

我们调研了市面上主流的向量数据库,主要对比了这几个:Milvus、Qdrant、Weaviate、Pinecone、pgvector。

Milvus:

  • 优点:功能强大,支持各种索引类型和查询方式;分布式架构,水平扩展能力强;社区活跃,文档完善;有商业支持(Zilliz)
  • 缺点:部署和运维比较复杂,组件多;资源消耗较大;学习曲线较陡
  • 适合:大规模、高并发、复杂查询场景

Qdrant:

  • 优点:性能优秀,查询延迟低;Rust编写,内存占用小;部署简单,单二进制文件;API设计友好;支持标量过滤和混合查询
  • 缺点:分布式功能相对较新,大规模集群的稳定性还需要验证;社区比Milvus小一些
  • 适合:中大规模、追求性能和简单部署的场景

Weaviate:

  • 优点:内置向量化模块,不需要单独部署embedding服务;支持GraphQL查询;有丰富的模块生态;文档友好
  • 缺点:性能不如Milvus和Qdrant;资源消耗较大;定制化能力有限
  • 适合:快速原型、中小规模、需要内置向量化的场景

Pinecone:

  • 优点:全托管服务,零运维;性能稳定,扩展性好;支持丰富的功能
  • 缺点:闭源,成本高;数据在第三方,有隐私和合规风险;不能自主部署
  • 适合:不想自己运维、预算充足的团队

pgvector:

  • 优点:基于PostgreSQL,学习成本低;和关系型数据无缝集成;部署简单;事务支持好
  • 缺点:性能不如专门的向量数据库,大数据量下查询慢;扩展能力有限;高级功能少
  • 适合:小规模、已经在用PostgreSQL、向量查询不是核心场景的团队

我们的场景是:数据量五千万条,高并发查询,需要标量过滤和混合查询,需要自主部署,运维成本可控。

综合对比之后,我们最终选择了Qdrant。主要原因是:

  • 性能优秀,查询延迟低,能满足我们的性能需求
  • 部署简单,单二进制文件,运维成本低
  • 支持标量过滤、混合查询、多租户等我们需要的功能
  • Rust编写,内存占用小,硬件成本低
  • 社区活跃,发展速度快

Milvus虽然功能更强大,但部署和运维太复杂,我们团队没有足够的人力去维护。Pinecone虽然省心,但成本太高,而且有数据隐私的顾虑。pgvector性能不够,满足不了我们的需求。

迁移方案

选定了Qdrant之后,我们开始设计迁移方案。

迁移的最大挑战是:不能停机。我们的业务是7x24小时运行的,不能因为迁移而中断服务。所以,我们采用了"双写+灰度切换"的方案。

第一步,搭建新的Qdrant集群。我们用三台服务器搭建了Qdrant集群,配置了持久化存储和备份。同时,搭建了监控和告警,确保新集群的稳定运行。

第二步,数据全量迁移。我们写了一个迁移脚本,从旧数据库中读取所有数据,转换成Qdrant的格式,批量导入Qdrant。全量迁移花了大约六个小时,迁移了五千万条数据。迁移过程中,我们做了数据校验,确保数据的完整性和一致性。

第三步,双写。全量迁移完成之后,我们开启了双写模式:新数据同时写入旧数据库和Qdrant。这样,在迁移期间,两个数据库的数据保持一致。双写持续了一周,期间我们不断对比两个数据库的查询结果,确保一致性。

第四步,灰度切换。双写稳定运行一周之后,我们开始灰度切换。先把10%的查询流量切到Qdrant,观察性能和稳定性。没有问题之后,逐步增加到30%、50%、100%。整个灰度过程持续了三天。

第五步,停写旧数据库。全部流量切到Qdrant之后,我们停止了对旧数据库的写入,但保留旧数据库作为只读备份,持续了两周。确认没有问题之后,正式下线旧数据库。

整个迁移过程,从搭建新集群到下线旧数据库,持续了将近一个月。虽然时间比较长,但整个过程非常平稳,用户完全没有感知到迁移。

踩过的坑

迁移过程中,我们也踩了不少坑,这里分享几个典型的。

第一个坑,向量维度不一致。我们原来的数据库用的是768维的向量,新业务想用1024维的向量。一开始我们想直接在Qdrant中混用不同维度的向量,但Qdrant的一个collection只能有一种向量维度。解决方案是:建两个collection,一个存768维的旧数据,一个存1024维的新数据,查询的时候根据数据来源选择对应的collection。

第二个坑,标量过滤的性能。Qdrant的标量过滤功能很强大,但如果过滤条件太复杂,或者过滤后的结果集太大,查询性能会明显下降。我们一开始把所有的metadata都建了索引,结果索引占用了大量内存,查询反而变慢了。后来,我们只对常用的过滤字段建索引,并且优化了过滤条件,性能才恢复正常。

第三个坑,批量导入的速度。全量迁移的时候,我们一开始用的是单线程导入,速度很慢,五千万条数据估计要导入两天。后来,我们改成了多线程并发导入,并且调整了Qdrant的写入参数(比如关闭实时索引、增大写入缓冲区),导入速度提升了五倍,六个小时就完成了。

第四个坑,数据一致性。双写期间,我们发现偶尔会出现两个数据库数据不一致的情况。原因是旧数据库写入成功但Qdrant写入失败,或者反过来。解决方案是:增加了一个对账任务,每天定时对比两个数据库的数据,发现不一致就自动修复。同时,写入的时候加了重试机制,确保写入成功。

第五个坑,监控指标不熟悉。Qdrant的监控指标和旧数据库不一样,一开始我们不知道该看哪些指标,出了问题不能及时发现。后来,我们仔细研究了Qdrant的文档,配置了关键指标的告警,包括查询延迟、写入延迟、内存使用、磁盘使用、集群状态等,才建立起完善的监控体系。

这些坑,虽然给我们带来了一些麻烦,但也让我们对Qdrant有了更深的理解。

迁移后的效果

迁移完成之后,效果非常明显。

性能方面:

  • 查询延迟P99从原来的500毫秒以上,降到了80毫秒以内
  • 并发查询能力从原来的每秒两千次,提升到了每秒一万五千次
  • 写入吞吐量从原来的每秒两百条,提升到了每秒三千条

功能方面:

  • 支持了标量过滤,查询结果可以按时间、分类、权限等过滤
  • 支持了混合查询,向量搜索和关键词搜索结合,搜索准确率提升了30%
  • 支持了多租户,不同业务的数据完全隔离,安全性大大提升
  • 支持了实时写入,数据写入后立即可查,延迟在10毫秒以内

运维方面:

  • 水平扩展方便,增加节点只需要几分钟,不需要停机
  • 监控完善,出了问题能及时发现和定位
  • 备份恢复简单,每天自动备份,恢复时间在半小时以内

成本方面:

  • 硬件成本降低了,因为Qdrant内存占用小,原来需要三台高配置服务器,现在三台普通配置就够了
  • 运维成本降低了,部署和维护都比原来简单
  • 总体拥有成本比原来降低了约40%

用户反馈也很好,搜索速度变快了,搜索结果更准确了,新功能也能更快地上线了。

一些经验和建议

基于这次迁移的经验,给想做向量数据库选型或迁移的团队一些建议。

第一,需求先行。不要盲目追求功能强大或者性能顶尖的数据库,先搞清楚自己的需求。数据量多大、查询并发多少、需要哪些功能、预算多少、运维能力如何,这些都要想清楚。适合自己的,才是最好的。

第二,充分测试。选型的时候,一定要用自己的真实数据做测试。不要只看官方的benchmark,因为不同的数据分布和查询模式,性能差异很大。把候选数据库都部署起来,用自己的数据跑一遍,对比性能、功能、易用性。

第三,制定详细的迁移方案。迁移不是小事,一定要有详细的方案,包括全量迁移、增量同步、灰度切换、回滚方案等。特别是不能停机的业务,一定要设计好双写或者增量同步的方案,确保迁移过程中业务不中断。

第四,做好数据校验。迁移过程中,数据一致性是最重要的。一定要有数据校验机制,全量迁移之后要校验,双写期间要定期对账,确保两个数据库的数据一致。

第五,灰度切换。不要一次性把所有流量切到新数据库,要灰度切换,从小流量开始,逐步增加。观察性能、稳定性、错误率,没有问题再继续增加。一旦发现问题,随时可以切回去。

第六,保留回滚能力。迁移期间,一定要保留回滚的能力。如果新数据库出了问题,能快速切回旧数据库。不要急着下线旧数据库,等新数据库稳定运行一段时间之后再下线。

第七,文档和培训。迁移完成之后,要及时更新文档,包括架构图、运维手册、故障处理指南等。同时,对团队成员进行培训,让大家熟悉新数据库的使用和运维。

写在最后

这次向量数据库的选型和迁移,是我们团队今年做的比较有价值的一个项目。

它不仅解决了原来的性能和功能问题,也让我们对向量数据库有了更深的理解。更重要的是,我们积累了一套数据库迁移的方法论,以后再做类似的迁移,就有经验可循了。

向量数据库是AI时代的基础设施,随着AI应用的发展,它会越来越重要。选择一个合适的向量数据库,并且做好迁移和运维,对AI应用的稳定性和性能至关重要。

希望这次实战的经验,能给大家一些参考。如果你也在做向量数据库的选型或者迁移,欢迎交流分享。