最近在做一个图片查重的小项目,用的Milvus 2.3,索引类型是IVF_FLAT,nlist设了1024,数据量大概50万条128维向量。单机部署,16核32G内存,本地测试单条查询延迟还行,但上线后并发一高(大概200QPS),CPU直接飙到90%,响应时间从20ms涨到200ms+。自己试了调大nprobe、换HNSW索引,效果不明显。想问下各位大佬,这种场景是硬件瓶颈还是参数没调好?有没有必要上GPU或者换分布式方案?另外,业务上允许一点精度损失,像PQ量化这种是不是能换来性能提升?希望有实战经验的朋友指点一下,谢谢!
用向量数据库做相似图片检索,QPS上不去怎么优化?
全部回复
共 146 条这配置瓶颈不在硬件,更像IVF_FLAT在高并发下查全率太低导致的无效计算太多。你试试把nlist降到512同时把nprobe提到64,配合PQ量化把向量压到32维,QPS翻倍应该没问题。另外Milvus那边记得开内存映射,不然32G很容易被索引吃满触发swap。我们之前50万向量用HNSW+SQ8在同样硬件上稳过300QPS,你可以参照这个方向调。
说实话你这个配置单机扛200QPS确实有点勉强,但也没到必须上分布式的程度。IVF_FLAT在50万数据量下瓶颈主要在IO和CPU的平衡,nprobe调大虽然能提召回但检索耗时是线性涨的,建议试试把nlist降到512,然后nprobe固定在32左右,看下内存映射和磁盘预加载有没有做对。另外你这128维其实不算高,PQ量化完全值得试,比如PQ16就是每个向量压成16字节,内存占用直接降8倍,QPS翻个两三倍很轻松,而且你允许精度损失的话召回率掉1%以内基本无感。不过要注意PQ对数据分布敏感,最好先在你的图片特征上跑个召回率对比,别直接上生产。还有个容易忽略的点,Milvus的请求并发线程池和客户端连接数有没有调优,默认配置经常是瓶颈,比如max_connection_pool_size和查询超时时间。真要上GPU的话,你这数据量其实性价比不高,除非后续涨到千万级,不然换个思路把检索拆成粗排加精排,先用PQ粗筛再对top100做原始向量重排序,效果往往比单纯换索引好。分布式方案建议先别碰,运维成本直接翻倍,先把单机压榨干净再说。
你这配置跑50万向量,瓶颈大概率不在硬件,IVF_FLAT本身并发就不占优,200QPS下CPU满载很正常。既然允许精度损失,直接上IVF_PQ或者把nlist调小到512试试,量化后内存占用和延迟都会明显降下来。HNSW在你这数据量下反而更吃内存,不太建议。另外可以先确认下是不是请求本身有瓶颈,比如用了同步客户端导致连接池打满,换个异步方式可能比折腾索引更有效。
说实话你这配置跑200QPS确实有点勉强,但也不是完全没救。50万条数据用IVF_FLAT的话,nprobe调大反而会放大CPU瓶颈,建议先试试把nlist降到256或者512,同时把查询时的nprobe控制在16左右,这样能明显减少计算量。
PQ量化在这个场景下挺合适的,你既然能接受精度损失,直接用IVF_PQ把128维压到32维,内存占用直接降75%,QPS翻个两三倍问题不大。别急着上GPU,先把索引类型换成HNSW配合PQ,16G内存其实够用,但要注意efConstruction和M参数别拉太高。
另外你确认下是不是没用上多线程?Milvus的query_node可以配置线程池,16核机器至少开8个并发查询线程,这个经常被忽略。如果改了这些还不行,那再考虑分布式的事儿,不过50万量级真没必要。
说实话你这个配置跑200QPS确实有点为难了,瓶颈不在nprobe和索引类型上,IVF_FLAT本质就是暴力扫描候选集,50万向量在16核上并行度撑不住。建议先试下把nlist降到512,同时开Milvus的query timeout和连接池调优,能榨出30%性能。PQ量化值得搞,128维压到32维基本无感,延迟能砍一半以上,精度损失对查重场景完全可接受。如果还不行,那确实得上GPU了,不过单机用GTX 3090就够,没必要直接上分布式。
说实话你这个配置单机扛200QPS确实有点吃力,但我觉得还没到必须上GPU的程度。IVF_FLAT这个索引本质上是暴力扫描候选集,nlist=1024配合50万数据,每个查询要遍历的倒排链不短,nprobe调大只会让CPU更忙,延迟自然就上去了。你提到精度可以损失,那PQ量化绝对是首选,把128维压到比如32维或者16维,内存占用和计算量能降一个量级,QPS翻个两三倍问题不大。不过有个坑,PQ量化后的召回率下降可能比预期明显,建议先离线验证下业务容忍度。另外你试试调整Milvus的线程池和并发查询队列,有时候默认配置对高并发不友好,把maxThreadNum和queryQueue调小反而能减少线程切换开销。HNSW在高并发下其实不占优,图遍历的随机内存访问在CPU繁忙时更吃紧,除非你愿意把M和efConstruction调大,但那样内存又要涨。硬件上16核跑200QPS确实紧,但你可以先看看是不是向量距离计算没走SIMD指令集,Milvus编译时开了AVX512的话CPU还能再榨点油水。分布式的话先别急着上,数据量才50万,单机分片反而增加网络开销,把索引换成IVF_PQ,再配合缓存热点查询结果,200QPS应该能稳住。
说实话你这配置跑50万条128维,IVF_FLAT在200QPS下CPU飙到90%太正常了,瓶颈不在硬件,而在你查询时每个向量都得跟中心点算距离,nprobe调大只会让CPU更忙。HNSW效果不明显大概率是ef参数没跟着调,单靠换索引解决不了并发问题。PQ量化肯定值得试,你这业务允许精度损失,把128维压到32维甚至16维,内存占用和计算量直接降一个量级,QPS翻几倍不是梦。不过要提醒你,PQ的召回率会受码本训练影响,最好先用测试集验证下误检率能不能接受。另外,Milvus 2.3有个坑,就是查询时默认会把原始向量加载到内存,你32G内存跑50万条其实已经很吃紧了,可以考虑把索引改成DiskANN或者MMap模式,把部分数据放磁盘,但要注意延迟波动。还有个更简单的思路,既然允许精度损失,直接先用粗排(比如中心点距离)筛出top1000,再对这批做精确计算,比单纯调索引参数有效得多。最后,别急着上GPU,你的数据量还没到那个规模,先把量化做了,再把查询并发压到客户端限流,200QPS应该能稳住。你要是真想上分布式,至少得等数据量到千万级再说,现在纯属浪费机器。
说实话你这配置跑200QPS确实有点悬,128维50万条IVF_FLAT本身就不是为高并发设计的,瓶颈主要在CPU的暴力计算上。PQ量化肯定值得试,精度损失如果业务能接受,4位或8位编码能直接把内存占用和距离计算量砍一大截,QPS翻个两三倍不难。另外建议把nprobe从默认值调小到16或32试试,你这场景查重精度要求没那么苛刻,召回率稍微降点换延迟挺划算的。真要上GPU的话,单张T4跑这种量级的检索绰绰有余,但得看你们有没有现成卡,分布式反而没必要,50万条数据太小了,加了集群光网络开销就够喝一壶的。
50万向量真不算大,你这配置单机应该能扛住的,问题大概率出在IVF_FLAT的粗查上,nprobe调大反而会让CPU更早爆。建议先把nlist降到256试试,同时把segment合并一下,小文件太多也会拖垮并发。PQ量化在这个量级上收益挺明显的,128维压到32维基本无损,QPS翻倍不是问题,不过记得先验证下业务对精度的容忍度。分布式真没必要,等数据量过千万再考虑。
50万向量真不算大,你这配置瓶颈大概率在CPU和内存带宽上,IVF_FLAT本身就要暴力算距离,200QPS等于每秒要跑一亿次向量计算,不爆才怪。PQ量化值得试,但记得先拿召回率做AB测试,我这边之前压到1/8维度,QPS翻了四倍多,精度掉了不到2%。另外你nprobe调到64以上收益就很小了,反而把内存带宽吃满,可以试试在Milvus里开mmap把索引映射到磁盘,省出内存给系统缓存。真要上GPU的话,单张3090能扛住你这场景,但分布式真没必要,数据量还没到那个级别。
500万以下数据IVF_FLAT确实不该这么拉胯,建议先查下segment数量和CPU降频,PQ量化配合HNSW肯定能压到50ms内。
50万向量真不大,先看下资源隔离和连接池,200QPS卡成这样大概率是没用对索引参数。
PQ量化确实能省内存降延迟,但你得先确认一下是不是CPU在跑距离计算时成了瓶颈。
说实话你这配置跑200QPS确实有点吃力,但也没到必须上GPU的地步。IVF_FLAT在50万数据量下并发瓶颈主要卡在CPU的暴力扫描上,试试把nprobe调小到8~16,同时加个缓存层扛热点,能把延迟压下来不少。PQ量化对你这场景挺划算的,精度损失换3~5倍吞吐提升,建议先上PQ+IVF试试。另外Milvus的配置文件里search的并发线程数记得调低点,默认值经常把CPU打满。
你这情况大概率不是硬件瓶颈,16核跑200QPS按理说够用。IVF_FLAT主要瓶颈在磁盘IO和CPU距离计算,50万向量其实不算大,试试把nlist调到2048或者4096,配合nprobe控制在8-16,能明显减少无效扫描。PQ量化肯定值得试,4位或8位量化对精度影响不大,但延迟能降好几倍,我这边之前512维数据用PQ后QPS翻了3倍。还有个思路,如果查重不要求绝对实时,可以加一层布隆过滤器先粗筛,能挡掉不少无效查询。分布式先别考虑,单机调优空间还很大。
50万向量真不算大,你这配置单机跑200QPS应该有余量,问题大概率出在IVF_FLAT的探测开销上,nprobe调到64以上并发时CPU肯定炸。既然允许精度损失,直接上PQ或者IVF_PQ,量化后内存占用和计算量都降一个量级,QPS翻倍很轻松。另外建议查下Milvus的线程池和连接数配置,16核机器默认参数往往吃不满CPU。GPU我觉得没必要,先试试把索引换成HNSW再加个缓存层,命中率高的话响应时间能压下来。
50万向量真不算大,你这配置单机跑200QPS按理说不该这么拉胯,先查下召回率和CPU热点是不是在距离计算上。IVF_FLAT瓶颈就在暴力算距离,nprobe调大只会更慢,换HNSW如果参数没跟着调也白搭。PQ量化肯定值得试,你这业务允许精度损失的话,直接上IVF_PQ能把内存占用和延迟都降下来,QPS翻几倍没问题。还有检查下Milvus的线程池和连接数配置,200并发可能把资源都耗在排队上了。别急着上GPU,先把量化做了看看,大概率够用。
说实话这配置跑50万向量200QPS确实到瓶颈了,IVF_FLAT本质还是暴力扫倒排桶,CPU全耗在距离计算上。建议先试试PQ+IVF,数据量才50万,量化到16维甚至8维精度损失很小但吞吐能翻几倍。另外nprobe别调太大,8到16就够,你单条延迟低估计是nprobe设小了,并发一高反而CPU爆炸。分布式就别想了,你这数据量上分布式纯属浪费运维精力,GPU更是没必要。
试试把IVF_FLAT换成IVF_PQ,nprobe调到64,召回够用的话QPS能翻几倍,你这配置瓶颈多半在CPU。
你这配置CPU扛不住很正常,50万向量真不算多,瓶颈大概率不在数据量而在并发查询时的CPU密集计算。IVF_FLAT的nprobe调大只会更吃CPU,试试PQ量化吧,你这业务允许精度损失,压到128维变32维左右,QPS翻几倍问题不大。另外Milvus 2.3有个坑,记得把查询的cache预热开起来,不然刚上线那会儿延迟会虚高。硬件的话16核跑200QPS确实勉强,可以先看看是不是gRPC连接数和线程池没调,这俩经常被忽略,调完再决定要不要上GPU。
PQ量化值得试,精度损失换3-5倍QPS很划算,但记得先压测看召回率能不能接受。