🚀 Попробуйте Zilliz Cloud, полностью управляемый Milvus, бесплатно — ощутите 10-кратное увеличение производительности! Попробовать сейчас>

milvus-logo
LFAI
Главная
  • Руководство по администрированию
    • Ресурсные группы
  • Home
  • Docs
  • Руководство по администрированию

  • Ресурсные группы

  • Управление группами ресурсов

Управление группами ресурсов

В Milvus можно использовать группу ресурсов, чтобы физически изолировать определенные узлы запросов от других. В этом руководстве рассказывается о том, как создавать и управлять пользовательскими группами ресурсов, а также перемещать узлы между ними.

Что такое группа ресурсов

Группа ресурсов может содержать несколько или все узлы запросов в кластере Milvus. Вы решаете, как распределить узлы запросов между группами ресурсов, исходя из того, что для вас наиболее целесообразно. Например, в сценарии с несколькими коллекциями можно выделить соответствующее количество узлов запросов для каждой группы ресурсов и загрузить коллекции в разные группы ресурсов, чтобы операции внутри каждой коллекции были физически независимы от операций в других коллекциях.

Обратите внимание, что экземпляр Milvus поддерживает ресурсную группу по умолчанию для хранения всех узлов запросов при запуске и называет ее __default_resource_group.

Начиная с версии 2.4.1, Milvus предоставляет декларативный API групп ресурсов, в то время как старый API групп ресурсов был устаревшим. Новый декларативный API позволяет пользователям достичь идемпотентности, чтобы упростить вторичную разработку в облачных нативных средах.

Понятия группы ресурсов

Группа ресурсов описывается конфигурацией группы ресурсов:

{
    "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.

За исключением следующих случаев:

  • Когда количество QueryNodes в кластере Milvus недостаточно, т.е. NumOfQueryNode < sum(.requests.nodeNum), всегда будут существовать группы ресурсов без достаточного количества QueryNodes.
  • Когда количество QueryNodes в кластере Milvus избыточно, т.е. NumOfQueryNode > sum(.limits.nodeNum), избыточные QueryNodes всегда будут размещаться в __default_resource_group первыми.

Конечно, если количество QueryNodes в кластере изменится, Milvus будет постоянно пытаться подстроиться под конечные условия. Поэтому можно сначала применить изменения в конфигурации группы ресурсов, а затем выполнить масштабирование QueryNode.

Использование декларативного api для управления группой ресурсов

Все примеры кода на этой странице приведены в версии PyMilvus 2.5.4. Перед их выполнением обновите свою установку PyMilvus.

  1. Создайте группу ресурсов.

    Чтобы создать группу ресурсов, выполните следующие действия после подключения к экземпляру 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.")
    
  2. Список групп ресурсов.

    Создав группу ресурсов, вы можете увидеть ее в списке групп ресурсов.

    Чтобы просмотреть список групп ресурсов в экземпляре Milvus, выполните следующие действия:

    rgs = milvus_client.list_resource_groups()
    print(f"Resource group list: {rgs}")
    
    # Resource group list: ['__default_resource_group', 'rg']
    
  3. Опишите группу ресурсов.

    Вы можете попросить 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
    
  4. Передача узлов между группами ресурсов.

    Вы можете заметить, что в описанной группе ресурсов еще нет ни одного узла запроса. Переместите несколько узлов из стандартной группы ресурсов в создаваемую следующим образом: предположим, что в настоящее время в __default_resource_group кластера находится 1 узел запросов, и мы хотим перенести один узел в созданную 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.
    
  5. Загрузка коллекций и разделов в группу ресурсов.

    Как только в группе ресурсов появятся узлы запросов, можно загружать коллекции в эту группу ресурсов. В следующем фрагменте предполагается, что коллекция с именем 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 загружал каждую реплику коллекции в отдельную группу ресурсов, убедитесь, что количество групп ресурсов равно количеству реплик.

  6. Передача реплик между группами ресурсов.

    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.
    
  7. Сбросить группу ресурсов.

    Вы можете в любой момент отказаться от группы ресурсов, в которой нет узла запроса (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 в облачной среде:

  1. По умолчанию Milvus создает __default_resource_group. Эта группа ресурсов не может быть удалена, а также служит группой ресурсов загрузки по умолчанию для всех коллекций, и к ней всегда назначаются избыточные QueryNodes. Поэтому мы можем создать ожидающую группу ресурсов для хранения неиспользуемых ресурсов QueryNode, предотвращая занятие ресурсов QueryNode группой __default_resource_group.

    Кроме того, если мы строго соблюдаем ограничение sum(.requests.nodeNum) <= queryNodeNum, мы можем точно контролировать распределение QueryNodes в кластере. Предположим, что в настоящее время в кластере есть только один 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. Кроме того, мы убеждаемся, что для другой группы ресурсов приоритетным является восстановление недостающих или избыточных QueryNodes из __pending_nodes.

  2. Масштабирование кластера

    Предположим, что у нас есть следующая функция масштабирования:

    
    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.
    
  3. Масштабирование кластера

    Аналогично, мы можем установить правила масштабирования, которые определяют приоритет выбора QueryNodes из группы ресурсов __pending_nodes. Эту информацию можно получить через 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, прочтите следующее: