管理資源群組
在 Milvus 中,您可以使用資源群組,將某些查詢節點與其他節點實體隔離。本指南將教您如何建立和管理自訂資源群組,以及在資源群組之間轉移節點。
什麼是資源群組
一个资源组可以容纳 Milvus 集群中的几个或所有查询节点。您可以根据对您最有意义的方式来决定如何在资源组之间分配查询节点。例如,在多集合場景中,您可以為每個資源群組分配適當數量的查詢節點,並將集合載入不同的資源群組,以便每個集合中的作業與其他集合中的作業在物理上獨立。
請注意,一個 Milvus 實例會維護一個預設的資源群組,以在啟動時存放所有查詢節點,並將其命名為__default_resource_group 。
從版本 2.4.1 開始,Milvus 提供了宣告式的資源群組 API,而舊的資源群組 API 已經被廢棄。新的宣告式 API 能讓使用者達到idempotency,更容易在雲原生環境中進行二次開發。
資源群組的概念
資源群組由資源群組 config 描述:
{
"requests": { "nodeNum": 1 },
"limits": { "nodeNum": 1 },
"transfer_from": [{ "resource_group": "rg1" }],
"transfer_to": [{ "resource_group": "rg2" }]
}
- requests 屬性指定資源群組必須符合的條件。
- limits屬性指定資源群組的最大限制。
- transfer_from和transfer_to 屬性分別描述資源群組最好從哪些資源群組取得資源,以及將資源轉移到哪些資源群組。
一旦資源群組的配置發生變化,Milvus 會根據新的配置盡可能調整當前查詢節點的資源,確保所有資源群組最終都能滿足以下條件:
.requests.nodeNum < nodeNumOfResourceGroup < .limits.nodeNum.
下列情況除外:
- 當 Milvus 集群中的 QueryNodes 數量不足時,即
NumOfQueryNode < sum(.requests.nodeNum)
,總會有資源群組沒有足夠的 QueryNodes。 - 當 Milvus 叢集中的 QueryNodes 數量過多時,即
NumOfQueryNode > sum(.limits.nodeNum)
,多餘的 QueryNodes 總會先被放置在__default_resource_group中。
當然,如果群集中的 QueryNodes 數量發生變化,Milvus 會不斷嘗試調整以滿足最終條件。因此,您可以先套用資源群組組態變更,然後再執行 QueryNode 擴充。
使用宣告式 api 管理資源群組
本頁面的所有程式碼範例都在 PyMilvus 2.5.4 中。在執行它們之前,請先升級您的 PyMilvus 安裝。
建立資源群組
要建立一個資源群組,請在連線到 Milvus 實例後執行下列步驟。以下片段假設
default
是您 Milvus 連線的別名。import pymilvus # A resource group name should be a string of 1 to 255 characters, starting with a letter or an underscore (_) and containing only numbers, letters, and underscores (_). name = "rg" node_num = 0 # create a resource group that exactly hold no query node. try: milvus_client.create_resource_group(name, config=ResourceGroupConfig( requests={"node_num": node_num}, limits={"node_num": node_num}, )) print(f"Succeeded in creating resource group {name}.") except Exception: print("Failed to create the resource group.")
列出資源群組。
建立資源群組後,您可以在資源群組清單中看到它。
要查看 Milvus 实例中的资源组列表,请执行以下操作:
rgs = milvus_client.list_resource_groups() print(f"Resource group list: {rgs}") # Resource group list: ['__default_resource_group', 'rg']
描述資源群組。
您可以讓 Milvus 以下列方式描述資源群組:
info = milvus_client.describe_resource_group(name) print(f"Resource group description: {info}") # Resource group description: # ResourceGroupInfo: # <name:rg1>, // resource group name # <capacity:0>, // resource group capacity # <num_available_node:1>, // resource group node num # <num_loaded_replica:{}>, // collection loaded replica num in resource group # <num_outgoing_node:{}>, // node num which still in use by replica in other resource group # <num_incoming_node:{}>, // node num which is in use by replica but belong to other resource group # <config:{}>, // resource group config # <nodes:[]> // node detail info
在資源群組之間轉移節點。
您可能會注意到所描述的資源群組還沒有任何查詢節點。從預設資源群組移動一些節點到您建立的資源群組,如下所示: 假設目前群組的__default_resource_group中有 1 個 QueryNodes,而我們想要移動一個節點到建立的rg。
update_resource_groups
確保多重組態變更的原子性,因此 Milvus 看不到任何中間狀態。source = '__default_resource_group' target = 'rg' expected_num_nodes_in_default = 0 expected_num_nodes_in_rg = 1 try: milvus_client.update_resource_groups({ source: ResourceGroupConfig( requests={"node_num": expected_num_nodes_in_default}, limits={"node_num": expected_num_nodes_in_default}, ), target: ResourceGroupConfig( requests={"node_num": expected_num_nodes_in_rg}, limits={"node_num": expected_num_nodes_in_rg}, ) }) print(f"Succeeded in move 1 node(s) from {source} to {target}.") except Exception: print("Something went wrong while moving nodes.") # After a while, succeeded in moving 1 node(s) from __default_resource_group to rg.
將集合和分割載入資源群組。
一旦資源群組中有查詢節點,您就可以載入集合到這個資源群組。以下片段假定已經存在一個名為
demo
的集合。from pymilvus import Collection collection_name = "demo" # Milvus loads the collection to the default resource group. milvus_client.load_collection(collection_name, replica_number=2) # Or, you can ask Milvus load the collection to the desired resource group. # make sure that query nodes num should be greater or equal to replica_number resource_groups = ['rg'] milvus_client.load_collection(replica_number=2, _resource_groups=resource_groups)
此外,您也可以直接將分割載入資源群組,並將其複本分佈在多個資源群組中。以下假設一個名為
Books
的集合已經存在,而且它有一個名為Novels
的分割區。collection = "Books" partition = "Novels" # Use the load method of a collection to load one of its partition milvus_client.load_partitions(collection, [partition], replica_number=2, _resource_groups=resource_groups)
請注意,
_resource_groups
是一個可選參數,不指定它會讓 Milvus 將複製本載入預設資源群組中的查詢節點。若要 Milus 在單獨的資源群組中載入集合的每個複製本,請確保資源群組的數量等於複製本的數量。
在資源群組之間轉移副本。
Milvus 使用副本实现分布在多个查询节点上的段之间的负载平衡。您可以按以下方式將資料集中的某些複製品從一個資源群組移到另一個資源群組:
source = '__default_resource_group' target = 'rg' collection_name = 'c' num_replicas = 1 try: milvus_client.transfer_replica(source, target, collection_name, num_replicas) print(f"Succeeded in moving {num_replicas} replica(s) of {collection_name} from {source} to {target}.") except Exception: print("Something went wrong while moving replicas.") # Succeeded in moving 1 replica(s) of c from __default_resource_group to rg.
刪除資源群組。
您可以隨時刪除沒有查詢節點的資源群組 (
limits.node_num = 0
)。在本指南中,資源群組rg
現在有一個查詢節點。您需要先將資源群組limits.node_num
的配置變更為零。resource_group = "rg try: milvus_client.update_resource_groups({ resource_group: ResourceGroupConfig( requests={"node_num": 0}, limits={"node_num": 0}, ), }) milvus_client.drop_resource_group(resource_group) print(f"Succeeded in dropping {resource_group}.") except Exception: print(f"Something went wrong while dropping {resource_group}.")
如需詳細資訊,請參閱pymilvus 中的相關範例。
管理集群擴充的好方法
目前,在雲原生環境中,Milvus 無法獨立進行擴充。但是,通過使用Declarative Resource Group API與容器協調,Milvus 可以輕鬆實現 QueryNodes 的資源隔離和管理。 以下是在雲環境中管理 QueryNodes 的良好實踐:
預設情況下,Milvus 會建立一個__default_resource_group 。此資源群組無法刪除,同時也是所有集合的預設載入資源群組,多餘的 QueryNodes 總是會被指派給它。因此,我們可以建立一個待定資源群組,來存放未使用的 QueryNode 資源,防止 QueryNode 資源被__default_resource_group 所佔用。
此外,如果我們嚴格執行約束
sum(.requests.nodeNum) <= queryNodeNum
,就可以精確地控制群集中 QueryNode 的分配。讓我們假設目前叢集中只有一個 QueryNode,並初始化叢集。 以下是一個設定範例:from pymilvus.client.types import ResourceGroupConfig _PENDING_NODES_RESOURCE_GROUP="__pending_nodes" def init_cluster(node_num: int): print(f"Init cluster with {node_num} nodes, all nodes will be put in default resource group") # create a pending resource group, which can used to hold the pending nodes that do not hold any data. milvus_client.create_resource_group(name=_PENDING_NODES_RESOURCE_GROUP, config=ResourceGroupConfig( requests={"node_num": 0}, # this resource group can hold 0 nodes, no data will be load on it. limits={"node_num": 10000}, # this resource group can hold at most 10000 nodes )) # update default resource group, which can used to hold the nodes that all initial node in it. milvus_client.update_resource_groups({ "__default_resource_group": ResourceGroupConfig( requests={"node_num": node_num}, limits={"node_num": node_num}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], # recover missing node from pending resource group at high priority. transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], # recover redundant node to pending resource group at low priority. )}) milvus_client.create_resource_group(name="rg1", config=ResourceGroupConfig( requests={"node_num": 0}, limits={"node_num": 0}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], )) milvus_client.create_resource_group(name="rg2", config=ResourceGroupConfig( requests={"node_num": 0}, limits={"node_num": 0}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], )) init_cluster(1)
使用上面的範例程式碼,我們建立一個名為__pending_nodes的資源群組,以存放額外的 QueryNodes。我們也建立兩個使用者特定的資源群組,分別命名為rg1和rg2。此外,我們確保另一個資源群組優先從__pending_nodes 恢復遺失或多餘的 QueryNodes。
叢集縮放
假設我們有以下的縮放功能:
def scale_to(node_num: int): # scale the querynode number in Milvus into node_num. pass
我們可以使用 API 將特定資源群組的 QueryNodes 擴充到指定的數量,而不影響任何其他資源群組。
# scale rg1 into 3 nodes, rg2 into 1 nodes milvus_client.update_resource_groups({ "rg1": ResourceGroupConfig( requests={"node_num": 3}, limits={"node_num": 3}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], ), "rg2": ResourceGroupConfig( requests={"node_num": 1}, limits={"node_num": 1}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], ), }) scale_to(5) # rg1 has 3 nodes, rg2 has 1 node, __default_resource_group has 1 node.
群集縮放
同樣地,我們可以建立 Scaling-in 規則,優先從__pending_nodes資源群組中選擇 QueryNodes。此資訊可透過
describe_resource_group
API 取得。達到擴充到指定資源群組的目標。# scale rg1 from 3 nodes into 2 nodes milvus_client.update_resource_groups({ "rg1": ResourceGroupConfig( requests={"node_num": 2}, limits={"node_num": 2}, transfer_from=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], transfer_to=[{"resource_group": _PENDING_NODES_RESOURCE_GROUP}], ), }) # rg1 has 2 nodes, rg2 has 1 node, __default_resource_group has 1 node, __pending_nodes has 1 node. scale_to(4) # scale the node in __pending_nodes
資源群組如何與多個複製品互動
- 單一集合的複製本與資源群組有 N 對 N 的關係。
- 當單一集合的多個複製本載入一個資源群組時,該資源群組的 QueryNodes 會平均分配給各個複製本,確保每個複製本的 QueryNodes 數目差異不超過 1。
下一步
要部署多租户 Milvus 实例,请阅读以下内容: