得物技術的 Milvus 探究與壓測分析

#01

背景

得物技術最近用到了向量搜索,所以要對 Milvus 進行壓測,同時爲了更加深入分析壓測中遇到的問題,也對 Milvus 的部分源碼與文檔進行了走讀,其中遇到了一些問題與疑惑,我們也直接與 Milvus 社區或開源貢獻者溝通。

通過壓測,我們發現某場景下存在 Milvus 的性能提升不上去的問題,並給出基於該場景的解決方案,社區反饋給 Milvus 官方。

以下爲 Milvus 的設計與壓測中遇到的一些問題與解決或跟進方案。

#02

向量搜索與 Milvus

2.1 向量搜索

向量搜索簡稱 ANNS,英文全稱 “Approximate Nearest Neighbor Search”,大致概念是從一堆向量中找出與某個目標向量距離最近的 N 個向量。最簡單粗暴的搜索方式是暴力搜索,但是可以通過擴增索引的方式加快搜索速度,提升大規模查詢的 QPS。

當前的向量索引可以分爲四大類:基於樹的索引、基於圖的索引、基於哈希的索引、基於量化的索引。其中圖思路由於較高的召回率、較好的性能和較多的後期優化思路,脫穎而出。

2.2 Milvus

Milvus(主要針對 2.0 以上版本)是一款雲原生向量數據庫,支持向量的插入,ANNS 搜索等。Milvus 能夠很好地應對海量向量數據,它集成了目前在向量相似性計算領域比較知名的幾個開源庫(Faiss,SPTAG 等),通過對數據和硬件算力的合理調度,以獲得最優的搜索性能。

#03

Milvus 架構介紹

3.1 Milvus 的數據集概念

數據集概念

  • collection:數據集,類似於 mysql 的表。

  • channel:基於主鍵把數據集細分爲很多 channel,在數據寫入與查詢時,對應與 msg borker 中的通道的概念。

  • partion:partion 把數據集進行了一層劃分,常見的 partion 比如日期,按照日期分類存儲數據,partion 與 channel 是正交的關係。

  • segment:Milvus 數據集的最小單位,具體的索引都是基於 segment 去構建的,查詢的最小單位也是 segment。

官網給出數據集讀取寫入例子:https://milvus.io/docs/v2.1.x/example_code.md

數據集查詢工具:https://github.com/milvus-io/birdwatcher

以下利用 birdwatcher 展示 collection 與 segment 信息:以上輸出結果,對該工具進行了改造。

具體一個 segment 在 etcd 中所有的信息:

3.2 Milvus 架構圖

Milvus 官網給出的架構圖如下:按照分組又可以分爲以下幾大類別:簡單介紹下以上各個微服務的功能:

  • 系統門面:

    • Proxy:所有 SDK 查詢都會經過 proxy,proxy 會把寫數據投遞到 message borker 中對應不同的 channel,proxy 會處理三類數據:寫請求,讀請求,控制類請求。
  • 系統協調者:

    • RootCoord:類似於傳統 master 角色主要做一些 DDL、DCL 的管理,比如:創建 Collection,刪除 Collection,或對於 partion 做管理。此外還有一個更大的責任,rootCoord 給系統分配全局唯一時間戳。
  • 寫數據:

    • DataCoord:協調者,分配,管理 segment,管理 dataNode,處理 dataNode 的故障恢復等。
    • DataNode:消費來自數據流的數據,進行數據序列化,負責把 log 數據轉成 log snapshot,刷新到磁盤中。
  • 索引創建:

    • IndexCoord:對 sealed SegMent 創建索引,管理 indexNode。
    • IndexNode:負責具體的索引創建事宜。
  • 查詢:

    • QueryCoord:數據查詢管理,負責管理 QueryNode。
    • QueryNode:負責具體的數據查詢事宜。
  • 元信息與元數據存儲:

    • MetaStore:metastore 使用 ETCD 存儲,主要負責元信息與元數據的存儲。比如:表結構,Segment 結構,全局時間戳等。
  • 寫數據消息投遞:

    • Log Borker:Log broker 採用了 pulsar。最新的 2.0 及以上版本中,寫入的數據都是先寫入 Log Broker,然後 DataNode 從 Log Broker 中讀取。
  • 數據與索引存儲:

    • Object Store:Object store 當前採用了 minio,主要用來存儲數據,索引等。

以上可以看出微服務比較多,微服務之間的通信方式主要有以下幾種:

#04

Milvus 向量寫入與讀取鏈路

4.1 Milvus 向量寫入路徑

  • Proxy 通過 produce 把數據寫入到 Message borker 的物理 channel 中。
  • DataNode 作爲消費者消費數據。
  • DataNode 定期把消費數據存到 Object store 中。
  • DataNode 會定期通知 dataCoord 記錄數據元信息。

4.2 Milvus 向量搜索路徑

以下當前最新版本 2.1.4 的讀流程,與網上的讀流程版本鏈路不同,應該是做了改造。

  • Proxy 收到向量搜索(ANNS)請求後,會把請求丟給 shard leader query node。

  • Leader querynode 會依據每個 segments 的分佈,把 ANNS 請求分發給每個 Query Node。Query Node 內部會基於最小搜索單位 Segment,cpu 核數等去做並行查詢,並做結果 reduce。

  • Proxy 收到所有的請求後,會對 search 結果做 reduce,並返回給客戶端。

#05

Milvus 壓測中的問題分析

壓測版本:Milvus-2.1.4

數據維度:512 dim

索引:

5.1 壓測結果

向量個數 索引 規格 QPS 99%耗時
十萬*512dim FLAT 2*(8cpu*16Gi) 880 82ms
十萬*512dim FLAT 2*(16cpu*16Gi) 1489 62ms
百萬*512dim FLAT 2*(16cpu*16Gi) 240 200ms
千萬*512dim FLAT 2*(16CPU*32Gi) 20 1.98s

5.2  壓測中遇到的問題與分析

  • QPS 與 CPU 使用率壓不上去,CPU 很難超過 50%(已經優化)。

    • 現象描述:壓測過程中,發現 QPS 始終壓不上去,仔細排查發現查詢節點的 cpu 使用率上不去,導致 QPS 也上不去。

    • 解決方案:初步懷疑是查詢節點調度問題,經過各種排查,發現與一個調度參數 scheduler.cpuRation 高度相關。以下是該參數在不同值的 QPS 情況。

規格 scheduler.cpuRation QPS
2*(8cpu*16Gi) 20 385
2*(8cpu*16Gi) 100 768
2*(8cpu*16Gi) 120 913
2*(8cpu*16Gi) 140 880

該參數主要用來評估一個 search task 的 cpu 使用情況,該參數越高,預示該 task 使用 cpu 越多,調度的時候,多個 task 去查詢的並行數量就會少一些。現在懷疑並行 task 太多,並不會達到很高的 QPS。

Milvus 並沒有公開該參數配置,已經通過 issue/enhancement 提給 Milvus 社區,後續版本應該會有所優化。

  • 擴容查詢節點後,短時間內 segments 沒有自動均衡(懷疑,跟進中)。

    • 現象描述:比如當前線上有兩個查詢節點,50 個 segments 均分在兩個 nodes 上。壓測中多次發現如果增加一個 node 後,segments 並不會自動均衡到新的 node 上。

    • 當前進度:整個壓測過程中做了三次寫入,有兩次沒有自動均衡,最後一次自動均衡了。跟 Milvus 社區維護人員諮詢過該問題,他們認爲理論上擴增是會自動均衡的。這與我們測出的結果不匹配,後續會繼續跟進,找到問題所在。

  • 持續大規模寫了很久後,會導致大量 growing segment,導致查詢性能下降(跟進中)。

    • 現象描述:多個線程,持續大規模插入向量數據後,通過日誌排查,發現部分部分查詢節點上的 segment 一直處於 growing 狀態,雖然這些 segment 在寫入節點已經 sealed 了,但是某個查詢節點並不會自動重新加載這些 sealed segments,而是一直認爲這些節點處於 growing 狀態。由於 growing 狀態的 segment 查詢時不用索引,而是暴力搜索,這樣會導致查詢變得比較慢,需要手動操作 release。

    • 當前進度:跟 Milvus 社區維護人員諮詢過該問題,後續還要持續跟進,找出原因並改進。

  • 版本升級後,原有數據不兼容(已有方案)。

    • 現象描述:Milvus 版本由 2.1.4 升級到最新版後,原有數據沒辦法加載,且啓動不了。回退版本後,發現數據元信息已經被寫壞了,沒法加載。
    • 解決方案:後續穩定後,謹慎做版本升級,或升級前做好充分調研。另外官方給出的建議是升級前先 merge 數據。
  • 千萬級別數據,壓測 QPS 不能達到預期(跟進中)。

    • 現象描述:當數據插入千萬級別後,發現壓測提升 QPS 比較難,99% 耗時下降也比較快,即使通過提升 cpu 核的個數,提升也不是很明顯。
    比如以下是使用兩個 32 核 16G:

    • 解決方案:這個可能跟我們使用 FLAT 索引有關,後續會嘗試新的索引方式壓測。
  • 不要通過 deployment 擴容縮容,儘量通過 helm 去操作。

    • 現象描述:當通過 deployment 擴容後,因爲參數不能統一修改的問題,做不到平滑擴容,比如擴容後可能需要重新 release 與 load 數據,造成短時間中斷。

所以官網也給出建議儘量通過 helm 去平滑擴容。

#06

總結

經過壓測,Milvus 是可以滿足我們當前業務場景的。以上壓測中的一些遺留問題,我們還在跟進中,比如:大量 growing segment 問題,節點擴增等問題。這些問題並不是 100% 出現的,有些是在我們極端測試條件下才出現的,後續我們還會持續測試,定位原因,並反饋給社區進一步優化。以上壓測的索引採用的是 FLAT,官方建議我們採用圖索引可以取得更高性能。由於我們當前的業務場景要用到 FLAT 索引,所以當前先基於 FLAT 索引去壓測,後續會用到圖索引,也會進行壓測。

通過對 Milvus 的壓測,順便了解並學習下 Milvus 的設計。總體來說 Milvus 是一款優秀的雲原生向量數據庫,它的一些設計理念還是比較先進的,把向量搜索與 k8s 結合在一起,通過簡單的查詢節點擴增便可以線性提升向量搜索的性能。對於一款分佈式數據庫,它實現了讀寫分離,存算分離,官網給出的文檔也比較豐富,工具也比較多,比如:attu,birdwatcher 等。


Zilliz 是向量數據庫系統領域的開拓者和全球領先者,研發面向 AI 生產系統的向量數據庫系統。Zilliz 以發掘非結構化數據價值爲使命,致力於打造面向 AI 應用的新一代數據庫技術,幫助企業便捷地開發 AI 應用。Zilliz 的產品能顯著降低管理 AI 數據基礎設施的成本,幫助 AI 技術賦能更多的企業、組織和個人。

本文分享自微信公衆號 - ZILLIZ(Zilliztech)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章