首页 / 开源项目 / 正文
开源项目

Qdrant向量数据库入门到精通:快速上手、性能调优与Milvus对比选型指南

chuanbook chuanbook
发布于 2026 年 10 月 08 日
阅读 约29分钟
浏览 6
评论 0

1.1 向量数据库与 Qdrant 的定位:解决什么问题

我第一次接触向量数据库是在做一个图片检索的小项目。当时面对几十万张图片,用传统的关键词搜索完全行不通,因为我根本无法用文字描述出每张图片的特征。朋友推荐我试试向量数据库,说它能理解"相似"这件事。带着好奇,我花了一个周末研究 Qdrant,结果发现这个东西确实解决了我长期以来的一个痛点。

传统数据库擅长精确匹配,比如查一个订单号、找一条用户记录。可现实世界里大量的数据是模糊的、连续的,图片、音频、文本语义、用户行为偏好,这些东西没法用等于号来比较。向量数据库做的事情是把这些数据转成一串浮点数,让机器能算出两个东西"有多像"。Qdrant 就是在这个赛道上做得很出色的一款开源产品,用 Rust 写的,性能好,API 设计也很干净。

我后来在好几个项目里用了 Qdrant,有商品推荐、文档问答、还有一次是做音频相似度匹配。它的定位很明确:给你一个能存向量、能快速找近邻、还能根据业务字段做过滤的引擎。你不用自己去实现 HNSW 算法,不用操心索引怎么建,把向量扔进去,它帮你把相似的东西找出来。这种"开箱即用"的感觉,对独立开发者和小团队特别友好。

1.2 Qdrant 核心概念:Collection、Point、Vector、Payload、Score

学 Qdrant 最开始让我懵的是那几个术语,Collection、Point、Payload,听起来和传统数据库不太一样。后来我用自己的话重新理解了一遍,一下子就通了。Collection 你可以当成一张表,但它是专门存向量的表。每个 Collection 里的所有向量维度必须一致,比如都必须是 768 维,不能混着来。这一点和关系型数据库的列类型约束有点像。

Point 是 Collection 里的基本单位,相当于一行记录。每个 Point 有一个 ID,有一个或多个 Vector,还可以带一份 Payload。Payload 是我最喜欢的部分,它是一个 JSON 对象,你可以往里塞任何元数据,商品价格、文章标题、发布时间、用户标签,想放什么放什么。搜索的时候可以基于 Payload 做过滤,比如"只在 2024 年发布的文章里找相似内容"。这个能力在实际项目里太重要了,光有向量相似度不够,业务规则得能叠加进去。

Score 是搜索结果的相似度分数。Qdrant 支持几种距离度量,Cosine、Euclidean、Dot Product,你建 Collection 的时候得指定一种。Score 的具体含义取决于你选的度量方式,Cosine 下分数越接近 1 越相似,Euclidean 下分数越小越相似。我一开始没注意这个区别,用 Euclidean 的时候看到分数是 0.02 还以为是 bug,其实是距离很近。搞清楚这几个概念,后面所有的操作都会顺很多。

1.3 环境搭建:Docker、本地安装、Python 客户端与 Web UI

我推荐所有刚上手的人直接用 Docker 跑 Qdrant,一行命令的事。docker run -p 6333:6333 qdrant/qdrant 敲下去,几秒钟就能起来。6333 是 HTTP 端口,6334 是 gRPC 端口,两个都挺有用。跑起来之后浏览器打开 http://localhost:6333/dashboard,能看到一个还挺好看的 Web UI,可以手动创建 Collection、看看里面的数据、甚至做搜索测试。对于刚学的人来说,这个可视化界面能帮你建立直觉。

如果你想在本地做开发,Python 客户端是首选。pip install qdrant-client 装好之后,几行代码就能连上服务。Qdrant 还提供了一个内存模式,QdrantClient(":memory:"),不启动 Docker 也能用,数据存在内存里,重启就没。这个模式特别适合写单元测试和快速试玩。我自己经常用它来验证一些查询逻辑,比每次都起一个容器方便多了。

除了 Python,Qdrant 官方还有 JavaScript、Go、Rust、Java 等客户端,覆盖得挺全。如果你不想用 SDK,直接发 HTTP 请求也完全可行,REST API 的文档写得很清楚。我个人习惯是原型阶段用 Python 客户端,生产环境里如果追求性能会切到 gRPC。Web UI 平时用来看看数据分布、手动调试一两个查询,比写脚本快。

1.4 快速上手:创建集合、写入向量、执行相似度搜索

我第一次跑通 Qdrant 的时候,整个过程不到十分钟。先建一个 Collection,指定向量维度是 4,距离度量用 Cosine。维度这个事得提前想清楚,因为一旦建好就不能改了。假如你用的是 OpenAI 的 text-embedding-3-small,维度是 1536;如果用 all-MiniLM-L6-v2,就是 384。选模型的时候顺手记一下维度,建 Collection 的时候直接填。

写入数据也挺直观。每个 Point 给一个 ID,给一个向量数组,再给一个 Payload 字典。我一般会把原始文本、标签、时间戳这些塞进 Payload,方便后面过滤和展示。批量写入的时候注意一次别塞太多,几千条一批比较稳妥。Qdrant 的写入是异步的,你可以在请求里加个 wait=true 让它同步返回,调试阶段挺好用,生产环境一般不加,追求吞吐。

搜索就是调 search 方法,传入一个查询向量,指定返回多少个结果。返回的每个结果里有 id、score、payload。我通常会设置 with_payload=True 和 with_vector=False,Payload 用来展示给用户看,向量一般不需要回传。加上 query_filter 就能做带条件的搜索,比如只在内网文档里找、只看价格低于 100 的商品。这套基础操作熟练之后,大部分业务场景都能覆盖了。

1.5 入门教程实战:构建一个最小语义搜索示例

我拿一个小例子演示一下完整流程。假设我有一堆技术文章的标题,想做一个语义搜索,输入"怎么调优数据库性能",能找出最相关的几篇。我用 sentence-transformers 的 all-MiniLM-L6-v2 把每篇文章标题转成 384 维向量,存进 Qdrant。查询的时候也把输入转成向量,然后搜 Top 3。

代码逻辑大概是这样:初始化客户端,创建名为 "articles" 的 Collection,向量大小 384,距离 Cosine。准备一个文章列表,循环 encode 成向量,构造 PointStruct 列表,批量 upsert。查询的时候把用户输入 encode 一下,调 search,打印结果。跑完之后你会发现,即使用词完全不重合,比如文章标题里写的是"索引优化",查询里说的是"性能调优",它也能给你找出来。这就是向量搜索的魔力所在。

这个例子我建议每个人都亲手跑一遍,不要直接抄代码就完事。自己在中间加打印,看看向量长什么样,score 是多少,Payload 有没有正确写入。改几个参数试试,把距离度量换成 Dot Product 看看结果有什么变化。动手折腾半小时,比看一整天文档理解得都深。做完之后你会对"向量数据库能干什么"有个非常具体的感受。

1.6 常见入门问题与排错:端口、维度、距离度量、数据持久化

端口冲突是新手最容易踩的坑。6333 和 6334 被别的服务占了的话,Docker 会报错但信息不太明显。我一般会先 lsof -i :6333 看一眼,确认没被用再启动。另外如果是在 WSL 或者远程服务器上跑,记得检查防火墙,浏览器打不开 dashboard 大概率是端口没放行。

维度不匹配这个错误信息其实挺明确的,但初学者容易忽略。Collection 建的时候是 384,你塞进去 1536 维的向量,它会直接拒绝。我的建议是在代码里把维度设成一个变量,建 Collection 和生成向量都用它,避免手抄数字抄错。距离度量选错了不会报错,但结果会很诡异。Cosine 适合大多数文本场景,Euclidean 适合图像特征,Dot Product 一般在向量已经归一化的情况下用。拿不准就用 Cosine,基本不会错。

数据持久化这块,Docker 跑的时候如果不挂 volume,容器一删数据就没了。生产环境一定要把 /qdrant/storage 挂出来。本地 :memory: 模式也只是测试用,别拿它存真数据。我有次图省事用内存模式跑了个 demo 给客户看,结果重启电脑后所有数据都没了,差点闹笑话。踩过这个坑之后,我养成了习惯,哪怕只是演示,也起个真正的容器挂上 volume,稳一点。

2.1 向量索引与量化:HNSW、标量量化、乘积量化与内存权衡

刚入门的时候我以为把向量丢进 Qdrant 就完事了,它会自动帮我找最近邻。跑到几万条数据的时候还挺快,等到数据量上了百万级,我发现搜索延迟开始不可控了。去翻文档才知道,Qdrant 默认用的是 HNSW 索引,一个近邻图结构,建索引本身有成本,但查询的时候不用全表扫描。这个机制决定了它的搜索速度是近似最近邻而不是精确最近邻,说白了就是用一点召回率换大量的速度提升。

HNSW 有两个关键参数我一直都在调:m 和 ef_construct。m 是每个节点连多少条边,值越大图越密,搜得越准但内存也越吃。ef_construct 是建索引时候的候选队列大小,开大一点索引质量好,建索引时间就长。我一般把 m 设成 16,ef_construct 设成 100 到 200 之间,这个范围覆盖了大部分场景。查询的时候还有个 hnsw_ef 参数,可以在搜索请求里动态调整,想快就调小,想准就调大,不用重建索引就能改,这点很舒服。

数据量再往上走,光靠 HNSW 内存扛不住。一个 768 维的 float32 向量占 3KB 左右,一千万条就是 30GB,普通服务器根本放不下。这时候就得上量化。标量量化(Scalar Quantization)把每个 float 从 32 位压到 8 位,内存直接降到四分之一,召回率损失通常在几个百分点以内,性价比非常高。我做的几个项目里默认都会开标量量化,除非业务对精度极其敏感。

乘积量化(Product Quantization)压缩率更夸张,能把向量压到原来的几十分之一。它把高维向量切成若干段,每段用一个码本里的中心点代替。好处是内存省得离谱,代价是精度掉得也明显。我试过在一亿条向量的场景下用量化,搜索速度飞快,可 Top 10 里偶尔会漏掉真正最相似的那几条。我的经验是,先用标量量化探一下底,扛不住再考虑乘积量化,而且要留一部分原始向量做重排序,弥补精度损失。

2.2 Payload 过滤与条件检索:精确匹配、范围、地理、嵌套过滤

纯向量搜索有个很大的问题:它只关心"像不像",不关心业务规则。我做过一个二手书交易平台的项目,用户搜索"算法导论",如果不过滤,搜出来一堆别人卖过的同款,点进去看早就卖掉了。这时候 Payload 过滤就派上用场了。你可以在搜索请求里加一个 query_filter,让它只在 status = "available" 的数据里找最近邻。

精确匹配是最常用的那种,match 条件,字段值等于某个值。等值判断可以用 keyword 类型,也可以用 integer、bool。字符串匹配的时候要注意,Qdrant 区分大小写,我踩过一次坑,存进去的是 "Available",查的时候写 "available",怎么都查不到,排查了半天。范围过滤用 range,gte、lte、gt、lt 都能用,价格区间、时间窗口这些场景特别顺手。日期字段我一般存成 Unix 时间戳的整数,范围查询走起来很快。

地理过滤是我觉得最惊喜的功能。Qdrant 支持 geo_radius 和 geo_bounding_box 两种地理条件,Payload 里存经纬度,搜索的时候直接限定"距离我 5 公里内"或者"某个矩形区域里"。共享单车找附近可用车辆、外卖平台找周边商家,这类需求用传统数据库加向量库得写不少胶水代码,Qdrant 原生就支持。我做过一个本地活动推荐的功能,用户定位上海静安区,只返回三公里内的活动,再按语义相关性排序,效果挺好。

嵌套过滤处理的是 Payload 里嵌套 JSON 结构的情况。比如一个商品的 metadata 字段下面还有 brand、color、size 这些子字段,你可以用点号路径去访问,也可以写嵌套的 must、should、must_not 组合条件。我遇到过最复杂的场景是电商筛选:颜色是红色或蓝色,价格在 100 到 500 之间,库存大于 0,品牌不是某几个屏蔽品牌。这种多条件组合 Qdrant 用布尔逻辑能表达得很清楚,写起来比想象中直观。

过滤和向量搜索的执行顺序也值得聊一下。Qdrant 不一定是先过滤再搜向量,它会根据过滤条件的筛选率做优化。如果过滤后剩下的数据很少,它可能直接暴力扫描这些数据算距离,反而比走 HNSW 图更快。这个策略是自动的,我平时不用管,但在压测的时候发现过,同一个查询加上不同过滤条件,延迟能差好几倍,原因就在这里。

2.3 混合搜索与多向量:稀疏向量、密集向量、重排序策略

我一开始对"混合搜索"这个词有点误解,以为是把两个向量拼一起。后来才搞明白,它说的是把稀疏向量和密集向量结合起来用。稀疏向量像 BM25 那种,基于词频,关键词命中就得分,擅长精确术语匹配。密集向量是语义向量,擅长理解同义表达,但对专有名词、型号、人名这类词容易抓瞎。两者互补,合起来效果比单用任何一种都好。

Qdrant 从 1.7 版本开始原生支持稀疏向量,可以给同一个 Point 同时挂密集向量和稀疏向量。查询的时候发两个请求,或者用 Query API 的 prefetch 机制把两路结果融合。融合策略有 RRF(Reciprocal Rank Fusion)和 DBSF(Distribution-Based Score Fusion),我一般用 RRF,它对分数尺度不敏感,稳定。举个例子,"iPhone 15 Pro Max 电池续航"这种查询,稀疏向量能保证"iPhone 15 Pro Max"这个词完整命中,密集向量负责理解"电池续航"的语义,两边结合召回质量提升明显。

多向量还有另一个用法:一个 Point 挂多个密集向量。比如一篇文章拆成多个段落,每段一个向量,都挂在同一个 Point 下面。或者一张商品图,有主图向量、细节图向量、标题向量,也放在一起。搜索的时候可以指定查哪个 vector name,返回的 Point 是完整的一条记录。这种设计省去了手动做聚合的麻烦,业务建模上也更自然。

重排序是我在生产环境里必做的一步。向量搜索出来的 Top 100 召回结果,用一个更重的模型再过一遍。可以是 cross-encoder,可以是业务规则加权,也能是 LLM 打分。Qdrant 本身不做重排序,但它返回的候选集质量够好,拿出去给别的组件处理很顺手。我做过一个文档问答,第一路 Qdrant 召回 100 条,第二路用 bge-reranker 精排出 Top 5 送给 LLM 做生成,答案质量比不重排高一大截。

2.4 性能调优:批量写入、分片、副本、搜索参数与召回率

写入性能这块我踩过不少坑。最开始一条一条 upsert,几万条数据跑了好几分钟,慢得让人怀疑人生。改成批量之后速度快了几十倍。批量大小我一般控制在 100 到 1000 之间,太小了网络开销占比高,太大了单次请求超时风险大。用 gRPC 客户端比 HTTP 快一些,特别是数据量大的时候差距能看出来。

还有一个参数叫 wait,默认是 false,写入请求发出去 Qdrant 就立刻返回,不等数据真正落盘。追求写入吞吐的时候这个默认值是对的,但如果写完马上要搜,可能搜不到刚写的数据,因为还在后台处理。调试或者对一致性要求高的场景,我加上 wait=true,慢一点但心里踏实。另外 ordering 参数可以控制并发写入的顺序,需要注意一下。

分片(sharding)是水平扩展的关键。一个 Collection 可以切成多个分片,分散到不同节点上。分片数量建 Collection 的时候指定,建好了改不了,得提前规划。分片太少,单节点压力大;分片太多,跨分片查询的协调开销上来了。我的经验是按预期的最终数据量来估,比如目标是一亿条向量,每个分片控制在 500 万到 1000 万条比较合适。副本(replica)则是为了高可用,一个分片跑多个副本,挂了一个还有备份。

搜索参数里最值得调的是 hnsw_ef 和 exact。exact=true 会跳过索引做暴力搜索,返回绝对精确的结果,代价是慢。做小规模数据集或者对精度要求极高的场景可以开。hnsw_ef 越大召回率越高,延迟也越高。我通常做一个召回率-延迟的曲线,找出业务能接受的那个平衡点。比如 95% 召回率对应的 hnsw_ef 是 128,那就固定用这个值。这个参数得靠压测数据说话,不能拍脑袋。

召回率评估这件事我一直想强调一下。向量搜索没有"正确答案"给你对,你得自己造测试集。我一般会从业务日志里抽 100 个真实查询,人工标注出应该命中的文档,然后跑搜索看命中率。这个测试集不用很大,但一定要真实,用合成数据测出来的召回率没意义。有了这个基准,你每次调参数都能量化看到效果,心里有底。

2.5 生产部署:Docker Compose、Kubernetes、分布式集群与监控

单机 Docker 跑着玩没问题,生产环境我基本都是 Docker Compose 或者 K8s 起步。Compose 适合中小规模,一台配置好点的机器,把 Qdrant 容器、存储卷、网络配好,重启策略设为 always,基本能稳定跑。关键点是把 /qdrant/storage 挂到宿主机上,再把配置通过 config.yaml 或者环境变量传进去。我见过有人没挂卷,升级的时候数据全丢,那种心情真的很难受。

数据量或者 QPS 上去之后,得上分布式集群。Qdrant 的分布式模式靠 Raft 协议做元数据一致性,多个节点组成集群,Collection 可以配置分片和副本。部署的时候有几个角色要分清:普通节点负责存数据和执行查询,还有 consensus 角色参与 Raft 选主。最小可用集群我建议三个节点起步,两个节点虽然能跑,但没有容错能力,挂一个整个集群就不可用了。

Kubernetes 上的部署可以用官方 Helm chart,也可以自己写 StatefulSet。我更倾向 Helm,它把配置、探针、PVC 都处理好了,省事儿。注意事项有几个:存储要用 SSD 的 PVC,别用网络盘,向量搜索对 IO 很敏感;资源请求和限制要留够,Qdrant 吃内存比较凶,OOM 被 kill 是很常见的翻车现场;用 headless service 让节点之间能互相发现,不然集群起不来。

监控这块 Qdrant 自带 Prometheus 格式的 metrics 端点,访问 /metrics 就能拉到。我主要盯几个指标:搜索 QPS、P95 延迟、召回相关指标、内存使用率、节点存活状态。Grafana 面板社区里有现成的模板,导进去改改就能用。日志方面建议单独收集,Qdrant 的日志里有不少有用的信息,比如慢查询、索引重建、副本同步异常。我配过 Alertmanager,内存超过阈值、节点掉线、搜索延迟飙升这些都设了告警,半夜被叫起来确实烦,但比用户投诉好。

2.6 数据管理:快照、备份恢复、版本升级与权限控制

快照是 Qdrant 内置的功能,可以给整个 Collection 或者整个实例打快照。我一般用 API 触发,POST /collections/{collection}/snapshots,返回一个快照文件。这个文件可以下载到本地,也可以存到 S3 之类的对象存储里。快照的粒度是 Collection 级别,整个实例级别的快照会把所有 Collection 都包进去。恢复的时候上传快照文件,Qdrant 会自动解压导入。

备份策略我通常配成每天一次全量快照,加上业务低峰期做。保留最近 7 天的,老的自动清理。快照文件不小,一个千万级的 Collection 可能有几十 GB,存储成本得算进去。另外快照期间对性能有一定影响,最好在流量低谷做。我见过有人高峰期打快照,结果整个集群卡了几分钟,用户侧全是超时。恢复演练也建议定期做一次,光备份不演练,真出事的时候可能发现恢复流程走不通。

版本升级要谨慎。Qdrant 的 minor 版本升级一般是向后兼容的,直接换镜像重启就行。major 版本升级前一定看 release notes,有时候存储格式会变,需要特殊迁移步骤。我升级前会做三件事:打一次完整快照、在测试环境跑一遍升级、确认客户端 SDK 版本兼容。生产环境升级的时候按节点滚动来,一次升一个,等它健康了再升下一个,别一把梭全升了。

权限控制这块 Qdrant 支持 API Key 和 JWT 两种方式。API Key 简单直接,在配置里加一个 service.api_key,所有请求带上这个 key 就行。JWT 更灵活,可以给不同的 token 配不同的权限,细到某个 Collection 的读、写、管理权限。多租户场景我一般用 JWT,给每个租户发一个 token,限定只能访问自己的 Collection。另外网络层面也要控制,别把 Qdrant 的端口直接暴露到公网,放在内网或者前面加一层网关。

2.7 应用集成:RAG、推荐系统、图像检索与异常检测

RAG 是我用 Qdrant 最多的场景。用户问一个问题,先把问题转成向量,在 Qdrant 里找到最相关的几段文档,把这几段作为上下文喂给 LLM,让它基于上下文生成回答。这里面 Qdrant 承担的是检索环节,是整个流程的基石。检索质量直接决定最终回答质量,所以我在这个环节下的功夫最多。Chunk 怎么切、用哪个 embedding 模型、要不要加混合搜索、要不要重排序,每个选择都影响效果。

推荐系统也是 Qdrant 的强项。用户行为向量、物品向量都存在里面,根据用户最近浏览或者购买过的物品,找到相似的推荐给用户。更复杂一点的做法是把用户所有行为向量做一个加权平均,作为用户画像向量,直接搜相似物品。实时性好的场景,用户刚点完一个商品,下一秒推荐列表就变了,Qdrant 的写入和搜索延迟都撑得住。我做过一个新闻推荐,用户每点一篇新闻,实时更新画像向量,推荐流几秒内就刷新,用户反馈挺正向的。

图像检索稍微特殊一点,因为图像向量一般比文本向量维度低,也不太适合混合搜索。做法是用 CLIP 或者类似的模型把图片编码成向量,存进 Qdrant。搜索的时候可以输入文字找图(跨模态),也可以输入一张图找相似的图。以图搜图在电商、版权检测、二次元社区里都有真实需求。我做过的场景是帮助用户找相似风格的壁纸,效果比标签搜索好太多,因为风格这种东西标签很难描述清楚。

异常检测是我今年才认真用起来的。做法是把正常样本的向量存进去,来了一条新数据,查它的最近邻。如果最近邻的距离都很大,说明这条数据很可能是异常的,跟历史模式对不上。日志异常检测、交易反欺诈、IoT 设备故障预警,这类问题都能这么搞。Qdrant 的搜索延迟很低,完全能支撑在线实时判断。我用它做过一段时间的服务日志监控,把每条日志的向量和过去一周的正常日志比,距离超阈值就告警,比传统的规则匹配少了很多误报。

这些应用场景侧面印证了一件事:Qdrant 的价值不在于它是个向量数据库,而在于它把向量检索这件事做得足够通用、足够快、足够省心,让开发者能专注在业务逻辑上。我推荐的路径是先从一个具体的小场景跑通,理解了写入、搜索、过滤、调优的完整链路之后,再去考虑更复杂的架构和部署。工具是给业务服务的,别为了用而用。

3.1 对比框架:为什么比较 Qdrant 与 Milvus

我做向量检索这几年,被问得最多的问题就是"到底选 Qdrant 还是 Milvus"。这两个算是开源向量数据库里最有代表性的两个项目了,一个主打轻量和开发体验,一个主打大规模和全功能。每次有人来问,我都不会直接给答案,因为选型这件事脱离了具体场景根本没法聊。我见过一个团队上来就上 Milvus 集群,结果数据量才几十万条,运维成本比业务本身还高。也见过有人拿 Qdrant 单机硬扛上亿数据,最后撑不住迁移得焦头烂额。

我比较这两个东西的时候有个自己的框架,大概分四层看。最底层是架构和部署形态,决定了你得花多少精力在运维上。往上是索引和查询能力,决定了它能不能满足你的检索精度和过滤需求。再往上是性能和扩展性,这层得用数据说话,不能看官方 benchmark 就下结论。最上层是生态和开发体验,包括 SDK、文档、社区活跃度。这四层我都跑过、踩过坑,下面每一节展开聊。

还有个事我想说在前面:这两个项目都在快速迭代,我今天写的对比可能几个月后就有变化。所以看这种对比文章,别把具体数字记死,要关注的是设计思路和取舍逻辑。理解了为什么这么设计,你才能判断未来某个新功能对你有没有价值。

3.2 架构与部署对比:单机、分布式、云托管与运维复杂度

Milvus 的架构我第一次看的时候头有点大。它从一开始就是奔着分布式去的,组件拆得很细:有接入层、协调层、工作节点、消息队列、对象存储。跑一个完整集群要起一堆容器,etcd、MinIO、Pulsar 或 Kafka 这些依赖一个都不能少。好处是每一层都能独立扩展,坏处是部署和维护的门槛上来了。我搭第一个 Milvus 集群的时候折腾了整整一个下午,各种组件之间的网络和配置问题。

Qdrant 的架构简洁得多。单机模式就是一个二进制或者一个 Docker 容器,起来就能用,存储直接落地到本地磁盘。分布式模式是靠 Raft 协议做集群,节点角色也没有拆得那么细。我用 Docker Compose 起一个三节点集群,配置文件写清楚就完事儿了,半小时能搞定。这种设计对中小团队特别友好,不需要专门配一个运维团队去伺候它。

云托管这块两家都有。Milvus 有 Zilliz Cloud,是原厂做的全托管服务,功能比较全。Qdrant 有 Qdrant Cloud,也支持混合云部署。我的经验是,如果你团队里没人愿意碰运维,直接上云托管省心,代价是成本会比自建高一些。云托管的另一个价值是版本升级、扩容这些操作都有人帮你兜底,出问题了有工单可以提。

我做过一个粗略的运维复杂度对比。Milvus 集群日常要盯的组件多,日志分散在不同地方,排查一个问题可能要翻好几个服务的日志。Qdrant 的组件少,出问题定位链路短。但从另一个角度说,Milvus 的组件化设计在超大规模场景下灵活性更高,单点故障的影响范围更好控制。这事儿得看团队的技术储备。

3.3 索引与查询能力对比:HNSW、IVF、量化、过滤与混合搜索

索引类型上 Milvus 给的选择更多。HNSW、IVF_FLAT、IVF_SQ8、IVF_PQ、DISKANN、SCANN 这些它都有,每种索引适合不同的数据规模和精度要求。DISKANN 是它比较有特色的一个,专门为磁盘存储设计,能在内存受限的情况下处理超大规模数据。我用它跑过十亿级别的数据集,内存占用确实比全内存方案低很多,代价是延迟会高一些。

Qdrant 的索引选择相对克制,主要是 HNSW 加上各种量化组合。它的思路是把 HNSW 这一个索引做到极致,通过标量量化、乘积量化、二值量化这些手段去调节内存和精度的平衡。我实际用下来,Qdrant 在中等规模数据下的开箱体验更好,默认参数就能跑出不错的效果。Milvus 的索引参数更多,调优空间大,但也意味着你得花更多时间去理解和实验。

过滤能力两边都支持,实现细节有差异。Qdrant 的 Payload 过滤做得特别细,精确匹配、范围、地理、嵌套布尔逻辑都能原生表达,而且过滤和向量搜索的执行计划会做优化。Milvus 的过滤是通过表达式语法做的,功能也全,但在复杂嵌套结构的表达上我觉得没有 Qdrant 直观。我做电商筛选那种多条件组合的场景,Qdrant 写起来更顺手。

混合搜索这块两家都在追。Qdrant 从 1.7 开始原生支持稀疏向量,多路召回融合有 RRF 和 DBSF 两种策略,用起来挺自然。Milvus 2.4 之后也支持稀疏向量和多向量搜索,功能上跟进了。我做过一个对比测试,同一个数据集上两边的混合搜索效果接近,差别主要在 API 的手感和文档的清晰度上。这块属于快速演进区,半年后再看可能又不一样。

3.4 性能与扩展性对比:延迟、吞吐、召回率、水平扩展与一致性

性能这块我做过不少压测,但每次压完我都提醒自己,benchmark 数据只能参考。我的测试环境规模有限,跟真正的生产环境差异很大。不过有些趋势是稳定的:小规模数据(百万级以下)单机场景,Qdrant 的延迟通常更低,因为它的架构简单,请求链路短。大规模集群场景,Milvus 的吞吐上限更高,因为它的组件化设计让写入和查询可以分别扩展。

延迟敏感的场景我会特别关注 P99。Qdrant 单机百万级数据,768 维向量,P99 延迟能压到几毫秒。Milvus 集群模式下,因为请求要经过多个组件,P99 会高一些,但换来的是更高的并发承载能力。我做过一个实时推荐的项目,要求 P99 在 20ms 以内,最后选了 Qdrant 单机加副本的方案,跑了一年多挺稳。

扩展性方面 Milvus 是它的主场。它支持从几个节点扩到几百个节点,分片和副本的管理都比较成熟。Qdrant 的分布式也能扩,但我在超大规模(十亿以上)场景下看到社区反馈的案例比 Milvus 少一些。这里得说清楚,绝大多数公司的数据量其实到不了那个级别,几千万到一亿条这个区间,两家的差距并不明显。

一致性模型两家有差异。Milvus 用的是最终一致性,写入后的数据可能会延迟一小段时间才能被搜到。Qdrant 在单机模式下是强一致的,分布式模式下可以通过 wait=true 参数控制一致性级别。我遇到过对实时性要求极高的场景,写完必须马上能搜到,Qdrant 的 wait=true 帮了大忙。Milvus 这块得靠应用层做补偿,复杂度高一些。

3.5 生态与开发体验对比:SDK、API、社区、文档与可观测性

SDK 覆盖上两家都挺全,Python、Java、Go、Node.js 都有官方客户端。我用得最多的是 Python 客户端,Qdrant 的 Python SDK 我觉得 API 设计更"Pythonic",类型提示完整,IDE 里自动补全体验好。Milvus 的 pymilvus 功能也很全,只是有些 API 的命名和参数组织我觉得不够直观,得经常翻文档。

REST API 方面 Qdrant 的设计我觉得更简洁,端点少,语义清晰,用 curl 调试很方便。Milvus 的 API 更复杂一些,因为它要暴露更多底层概念,比如 partition、index 这些。我教新人上手的时候,Qdrant 通常半天就能写出能跑的代码,Milvus 得花一两天理解它的架构概念。

文档质量我投 Qdrant 一票。它的官方文档结构清晰,有大量可运行的示例,概念解释也到位。Milvus 的文档内容很全,但组织上有点散,有时候找一个具体用法得在文档、GitHub issue、博客之间来回跳。社区活跃度两家都不错,Milvus 背靠 Zilliz,投入的资源多,Qdrant 的社区虽然小一些但响应很快,GitHub issue 里经常能看到维护者亲自回复。

可观测性两家都提供 Prometheus 指标。Milvus 的指标更细,因为它组件多,每个组件都有自己的指标要暴露。Qdrant 的指标相对精简,主要围绕搜索、写入、内存这些核心维度。我配 Grafana 面板的时候,Qdrant 的核心指标一页就够看,Milvus 的话得按组件分好几个面板。监控这件事不是越细越好,关键看你能不能快速定位到问题。

3.6 成本与适用场景对比:中小规模、大规模、实时检索与多租户

成本这块不能只看软件本身,得算总账。Milvus 因为组件多,硬件需求也高,一套能跑生产的最小集群至少三台像样的机器,加上消息队列和对象存储这些依赖。Qdrant 单机就能撑起中小规模业务,一台配置好的机器就够了。我算过一个案例,同样的数据量和 QPS,Qdrant 方案的硬件成本大概是 Milvus 集群方案的三到五分之一。

人力成本更值得算。Milvus 集群需要有人懂它的组件、会排查问题、会做容量规划。Qdrant 的运维门槛低很多,一个后端工程师顺手就能管起来。我见过一些团队为了用 Milvus,专门招了运维,结果那个人的大部分时间都在处理跟业务无关的集群问题。这种隐形成本算进总账里,选型的天平会明显倾斜。

中小规模场景我一般推荐 Qdrant。数据量几百万到几千万,QPS 几百到几千,Qdrant 单机或者主从就能搞定,性价比拉满。大规模场景(十亿以上、多租户、需要精细的资源隔离)Milvus 更合适,它的架构就是为这种场景设计的。实时检索两家都能做,但 Qdrant 在低延迟上有优势。多租户 Milvus 支持得更好,它有 database 和 collection 的多级隔离机制。

有个场景我特别想提一下:快速原型和 MVP。创业团队早期数据量小、需求变化快,用 Qdrant 能让你把精力全放在产品上。等业务跑起来了,数据量真上去了,再考虑要不要迁到 Milvus 也不迟。上来就上重架构,很多团队死在了还没见到用户就先把基础设施搞复杂了的阶段。

3.7 选型建议与迁移路径:从 Milvus 到 Qdrant 或并行使用

选型我给一个简单的判断逻辑。数据量在一亿条以下、团队规模不大、追求低延迟和快速开发,选 Qdrant。数据量在十亿以上、有多租户需求、团队里有专门的平台或基础设施工程师,选 Milvus。中间地带就看你的具体诉求,比如对延迟极度敏感就偏 Qdrant,对扩展性有明确规划就偏 Milvus。

迁移路径这块我做过从 Milvus 迁到 Qdrant 的项目。核心工作是数据导出、重新入库和验证召回效果。Milvus 可以导出 collection 里的所有向量和标量字段,Qdrant 导入的时候注意别名字段映射和向量维度的对齐。迁移的难点不在于搬数据,在于业务代码里调用的 API 得改,两边客户端的接口差异得一个个替换。我一般会写一层抽象层,把向量库的操作封装起来,这样换底层实现的时候业务代码不用大改。

反过来的迁移我也见过,Qdrant 撑不住往 Milvus 迁。这种通常是因为数据量增长超出了预期,单机加副本的模式已经压不住。迁移之前建议先做一次容量规划,搞清楚瓶颈到底在哪里。有时候问题不是向量库本身,是上游的 embedding 生成或者下游的重排序环节拖慢的,换库解决不了。

并行使用也是一条路。我见过一些团队把热数据放 Qdrant 追求低延迟,冷数据放 Milvus 省成本,中间用一个路由层做分发。这种架构复杂度上来了,得看业务价值撑不撑得住。我的建议是,除非有明确的、量化的收益,别轻易上多套向量库,运维负担和一致性问题是实打实的。

3.8 总结与展望:向量数据库趋势下 Qdrant 的定位

向量数据库这个赛道这两年热得发烫,各种新产品层出不穷。我的判断是,这个市场最后会分层。底层是通用的、大规模的基础设施,服务的是超大型客户和平台型公司。上层是轻量的、场景化的、开发体验好的产品,服务的是绝大多数普通团队。Qdrant 在后者里的位置挺清晰,它不追求做最全的功能,追求的是把核心体验做到最好。

从趋势上看,混合搜索、多模态、量化压缩这些能力会越来越成为标配。Qdrant 在这几个方向上跟得挺紧,稀疏向量支持、多种量化方案、Query API 的迭代速度都很快。它的社区也在成长,虽然体量还没到 Milvus 那个级别,但活跃度和口碑是往上走的。我关注它两年多了,版本迭代的节奏一直很稳。

对开发者来说,我的建议是别太纠结于选哪个"最好的"向量数据库,因为不存在。选一个能解决你当下问题、让你能快速把产品跑起来的就够了。Qdrant 在我这里是一个"默认选项"级别的工具,大部分场景下拿起来就能用。什么时候需要更重的方案,业务会告诉你。技术在演进,你的判断框架也得跟着长,但核心逻辑不会变:工具服务于业务,别本末倒置。

赞0
踩0
☆收藏0
版权声明
文章版权声明:除非注明,否则均为ZBLOG原创文章,转载或复制请以超链接形式并注明出处。
分享到
chuanbook

链接已复制到剪贴板