리소스 그룹 관리
Milvus에서는 리소스 그룹을 사용하여 특정 쿼리 노드를 다른 노드들로부터 물리적으로 분리할 수 있습니다. 이 가이드에서는 사용자 지정 리소스 그룹을 생성 및 관리하는 방법과 그룹 간에 노드를 이동하는 방법을 단계별로 안내합니다.
리소스 그룹이란?
리소스 그룹은 Milvus 클러스터 내의 여러 쿼리 노드 또는 모든 쿼리 노드를 포함할 수 있습니다. 사용자에게 가장 적합한 방식에 따라 리소스 그룹 간에 쿼리 노드를 어떻게 할당할지 결정할 수 있습니다. 예를 들어, 다중 컬렉션 환경에서는 각 리소스 그룹에 적절한 수의 쿼리 노드를 할당하고 컬렉션을 서로 다른 리소스 그룹에 로드함으로써, 각 컬렉션 내의 작업이 다른 컬렉션의 작업과 물리적으로 독립적으로 수행되도록 할 수 있습니다.
Milvus 인스턴스는 시작 시 모든 쿼리 노드를 포함하는 기본 리소스 그룹을 유지하며, 이를 __default_resource_group으로 명명합니다.
버전 2.4.1부터 Milvus는 선언형 리소스 그룹 API를 제공하며, 기존 리소스 그룹 API는 더 이상 사용되지 않습니다. 새로운 선언형 API를 통해 사용자는 항등성을 확보할 수 있어, 클라우드 네이티브 환경에서 2차 개발을 보다 쉽게 수행할 수 있습니다.
리소스 그룹의 개념
리소스 그룹은 리소스 그룹 구성으로 정의됩니다:
{
"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)인 경우, 항상 쿼리 노드가 충분하지 않은 리소스 그룹이 존재하게 됩니다. - Milvus 클러스터의 쿼리 노드 수가 과도할 경우(
NumOfQueryNode > sum(.limits.nodeNum)), 중복된 쿼리 노드는 항상 __default_resource_group에 우선 배치됩니다.
물론 클러스터 내 쿼리 노드(QueryNodes)의 수가 변경되면, Milvus는 최종 조건을 충족하도록 지속적으로 조정을 시도합니다. 따라서 먼저 리소스 그룹 구성 변경 사항을 적용한 다음 쿼리 노드(QueryNodes) 스케일링을 수행할 수 있습니다.
선언형 API를 사용하여 리소스 그룹 관리
이 페이지의 모든 코드 예제는 PyMilvus 3.0.1 버전입니다. 코드를 실행하기 전에 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개의 QueryNode가 있으며, 생성한 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가 복제본을 기본 리소스 그룹의 쿼리 노드에 로드합니다.Milvus가 컬렉션의 각 복제본을 별도의 리소스 그룹에 로드하도록 하려면, 리소스 그룹의 수가 복제본의 수와 같도록 해야 합니다.
리소스 그룹 간에 복제본을 이동합니다.
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을 0으로 변경해야 합니다.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는 클라우드 네이티브 환경에서 독립적으로 확장 및 축소할 수 없습니다. 그러나 선언형 리소스 그룹 API를 컨테이너 오케스트레이션과 함께 사용하면 Milvus는 쿼리 노드에 대한 리소스 격리 및 관리를 쉽게 구현할 수 있습니다. 다음은 클라우드 환경에서 쿼리 노드를 관리하기 위한 모범 사례입니다:
기본적으로 Milvus는 __default_resource_group을 생성합니다. 이 리소스 그룹은 삭제할 수 없으며, 모든 컬렉션에 대한 기본 로딩 리소스 그룹 역할을 하며, 중복 QueryNodes는 항상 이 그룹에 할당됩니다. 따라서, 사용되지 않는 쿼리노드 리소스를 보관할 임시 리소스 그룹을 생성하여, 쿼리노드 리소스가 __default_resource_group에 의해 점유되는 것을 방지할 수 있습니다.
또한, `
sum(.requests.nodeNum) <= queryNodeNum` 제약 조건을 엄격하게 적용하면 클러스터 내 쿼리 노드의 할당을 정밀하게 제어할 수 있습니다. 현재 클러스터에 쿼리 노드가 단 하나만 있다고 가정하고 클러스터를 초기화해 보겠습니다. 다음은 설정 예시입니다: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)위의 예제 코드를 사용하여 추가 QueryNode를 보관할 __pending_nodes라는 리소스 그룹을 생성합니다. 또한 rg1과 rg2라는 두 개의 사용자 전용 리소스 그룹을 생성합니다. 아울러 다른 리소스 그룹이 누락되거나 중복된 QueryNode를 __pending_nodes에서 우선적으로 복구하도록 설정합니다.
클러스터 스케일 아웃
다음과 같은 확장 기능이 있다고 가정해 봅시다:
def scale_to(node_num: int): # scale the querynode number in Milvus into node_num. passAPI를 사용하여 다른 리소스 그룹에 영향을 주지 않으면서 특정 리소스 그룹을 지정된 수의 쿼리 노드로 확장할 수 있습니다.
# 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.클러스터 스케일 인
마찬가지로, __pending_nodes 리소스 그룹에서 쿼리 노드를 우선적으로 선택하도록 스케일 인 규칙을 설정할 수 있습니다. 이 정보는
describe_resource_groupAPI를 통해 얻을 수 있습니다. 이를 통해 지정된 리소스 그룹의 스케일 인 목표를 달성할 수 있습니다.# 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 관계를 가집니다.
- 단일 컬렉션의 여러 복제본이 하나의 리소스 그룹에 로드되면, 해당 리소스 그룹의 쿼리 노드는 복제본들 사이에 균등하게 분산되어 각 복제본이 보유한 쿼리 노드 수의 차이가 1을 초과하지 않도록 보장합니다.
다음 단계
다중 테넌트 Milvus 인스턴스를 배포하려면 다음을 참조하십시오: