一致性等級
作為一個分散式向量資料庫,Milvus 提供多種一致性等級,以確保每個節點或副本在讀寫作業時能存取相同的資料。目前,支援的一致性等級包括Strong、Bounded、Eventually 和Session,其中Bounded是預設使用的一致性等級。
概述
Milvus 是一個將儲存和計算分開的系統。在這個系統中,資料節點 (DataNodes) 負責資料的持久化,並最終將資料儲存在分散式物件儲存空間 (例如 MinIO/S3)。QueryNodes負責處理搜尋等計算任務。這些任務涉及批次資料和串流資料的處理。簡單來說,批次資料可以理解為已經儲存於物件儲存空間的資料,而串流資料則是指尚未儲存於物件儲存空間的資料。由於網路延遲的關係,QueryNodes 通常無法保存最新的串流資料。如果沒有額外的保障措施,直接在串流資料上執行 Search 可能會導致許多未承諾的資料點遺失,影響搜尋結果的準確性。
Milvus 是一個將儲存和計算分開的系統。在這個系統中,DataNodes 負責資料的持久化,並最終將資料儲存於分散式物件儲存空間,例如 MinIO/S3。QueryNodes 負責處理搜尋等計算任務。這些任務涉及批次資料和串流資料的處理。簡單來說,批次資料可理解為已儲存在物件儲存空間的資料,而串流資料則是指尚未儲存在物件儲存空間的資料。由於網路延遲的關係,QueryNodes 通常無法儲存最新的串流資料。如果沒有額外的保障措施,直接在串流資料上執行 Search 可能會導致遺失許多未承諾的資料點,影響搜尋結果的準確性。
批次資料和串流資料
如上圖所示,QueryNodes 在收到 Search 請求後,可以同時接收串流資料和批次資料。然而,由於網路延遲,QueryNodes 取得的串流資料可能不完整。
為了解決這個問題,Milvus 會為資料佇列中的每條記錄加上時間戳,並持續在資料佇列中插入同步時間戳。每當收到同步時間戳 (syncTs) 時,QueryNodes 會將其設定為 ServiceTime,意即 QueryNodes 可以看到該 Service Time 之前的所有資料。在 ServiceTime 的基礎上,Milvus 可以提供保證時間戳 (GuaranteeTs) 來滿足使用者對一致性和可用性的不同要求。使用者可透過在其 Search 請求中指定 GuaranteeTs,告知 QueryNodes 在搜尋範圍中需要包含指定時間點之前的資料。
ServiceTime 與 GuaranteeTs
如上圖所示,如果 GuaranteeTs 小於 ServiceTime,表示指定時間點之前的所有資料已完全寫入磁碟,允許 QueryNodes 立即執行 Search 作業。當 GuaranteeTs 大於 ServiceTime 時,QueryNodes 必須等到 ServiceTime 大於 GuaranteeTs 時,才能執行 Search 作業。
使用者需要在查詢精確度與查詢延遲之間作出權衡。如果使用者對一致性要求很高,而且對查詢延遲不敏感,他們可以將 GuaranteeTs 設定為盡可能大的值;如果使用者希望快速收到搜尋結果,而且對查詢精確度的容忍度較高,那麼可以將 GuaranteeTs 設定為較小的值。
一致性等級說明
Milvus 提供四種不同 GuaranteeTs 的一致性等級。
強
使用最新的時間戳作為 GuaranteeTs,查詢節點必須等到 ServiceTime 符合 GuaranteeTs 才執行 Search 請求。
最終
GuaranteeTs 設定為極小的值,例如 1,以避免一致性檢查,這樣 QueryNodes 就可以在所有批次資料上立即執行 Search 請求。
有限制的延遲
GuranteeTs 設定為早於最新時間戳記的時間點,使 QueryNodes 在執行搜尋時可容忍某些資料遺失。
會話
用戶端插入資料的最新時間點作為 GuaranteeTs,使 QueryNodes 可以在用戶端插入的所有資料上執行搜尋。
Milvus 使用 Bounded Staleness 作為預設的一致性等級。如果未指定 GuaranteeTs,則使用最新的 ServiceTime 作為 GuaranteeTs。
設定一致性等級
您可以在建立資料集、執行搜尋和查詢時設定不同的一致性層級。
建立集合時設定一致性層級
當建立一個集合時,您可以為集合內的搜尋和查詢設定一致性層級。以下程式碼範例設定一致性等級為Strong。
client.create_collection(
collection_name="my_collection",
schema=schema,
# highlight-next
consistency_level="Strong",
)
CreateCollectionReq createCollectionReq = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
// highlight-next
.consistencyLevel(ConsistencyLevel.STRONG)
.build();
client.createCollection(createCollectionReq);
export schema='{
"autoId": true,
"enabledDynamicField": false,
"fields": [
{
"fieldName": "my_id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "my_vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5"
}
},
{
"fieldName": "my_varchar",
"dataType": "VarChar",
"isClusteringKey": true,
"elementTypeParams": {
"max_length": 512
}
}
]
}'
export params='{
"consistencyLevel": "Strong"
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": $params
}"
consistency_level
參數的可能值是Strong
,Bounded
,Eventually
, 和Session
。
在搜尋中設定一致性等級
您可以隨時變更特定搜尋的一致性等級。以下程式碼範例會將一致性層級設定回 Bounded。此變更只適用於目前的搜尋請求。
res = client.search(
collection_name="my_collection",
data=[query_vector],
limit=3,
search_params={"metric_type": "IP"},
# highlight-start
consistency_level="Bounded",
# highlight-next
)
SearchReq searchReq = SearchReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(queryVector))
.topK(3)
.searchParams(params)
.consistencyLevel(ConsistencyLevel.BOUNDED)
.build();
SearchResp searchResp = client.search(searchReq);
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"limit": 3,
"consistencyLevel": "Bounded"
}'
此參數在混合搜尋和搜尋迭代器中也可用。consistency_level
參數的可能值是Strong
,Bounded
,Eventually
, 和Session
。
在查詢中設定一致性層級
您可以隨時變更特定搜尋的一致性層級。以下程式碼範例設定一致性層級為Eventually。此設定僅適用於目前的查詢請求。
res = client.query(
collection_name="my_collection",
filter="color like \"red%\"",
output_fields=["vector", "color"],
limit=3,
# highlight-start
consistency_level="Eventually",
# highlight-next
)
QueryReq queryReq = QueryReq.builder()
.collectionName("my_collection")
.filter("color like \"red%\"")
.outputFields(Arrays.asList("vector", "color"))
.limit(3)
.consistencyLevel(ConsistencyLevel.EVENTUALLY)
.build();
QueryResp getResp = client.query(queryReq);
查詢迭代器中也可使用此參數。consistency_level
參數的可能值是Strong
,Bounded
,Eventually
, 和Session
。