• Über Milvus
  • Erste Schritte
  • Begriffe
  • Benutzerhandbuch
  • Datenimport
  • KI-Tools
  • Administrationshandbuch
  • Werkzeuge
  • Integrationen
  • Anleitungen
  • Häufig gestellte Fragen
  • API Reference

Ressourcengruppen verwalten

In Milvus können Sie eine Ressourcengruppe verwenden, um bestimmte Abfrageknoten physisch von anderen zu isolieren. Diese Anleitung führt Sie durch die Erstellung und Verwaltung benutzerdefinierter Ressourcengruppen sowie durch die Verschiebung von Knoten zwischen diesen Gruppen.

Was ist eine Ressourcengruppe?

Eine Ressourcengruppe kann mehrere oder alle Abfrageknoten eines Milvus-Clusters enthalten. Sie entscheiden selbst, wie Sie die Abfrageknoten auf die Ressourcengruppen verteilen möchten, je nachdem, was für Sie am sinnvollsten ist. In einem Szenario mit mehreren Sammlungen können Sie beispielsweise jeder Ressourcengruppe eine angemessene Anzahl von Abfrageknoten zuweisen und Sammlungen in verschiedene Ressourcengruppen laden, sodass die Vorgänge innerhalb jeder Sammlung physisch unabhängig von denen in anderen Sammlungen sind.

Beachten Sie, dass eine Milvus-Instanz beim Start eine Standard-Ressourcengruppe unterhält, die alle Abfrageknoten enthält, und diese als __default_resource_group bezeichnet.

Ab Version 2.4.1 bietet Milvus eine deklarative Ressourcengruppen-API an, während die alte Ressourcengruppen-API veraltet ist. Die neue deklarative API ermöglicht es Benutzern, Idempotenz zu erreichen und Sekundärentwicklungen in Cloud-nativen Umgebungen einfacher durchzuführen.

Konzepte der Ressourcengruppe

Eine Ressourcengruppe wird durch eine Ressourcengruppenkonfiguration beschrieben:

{
    "requests": { "nodeNum": 1 },
    "limits": { "nodeNum": 1 },
    "transfer_from": [{ "resource_group": "rg1" }],
    "transfer_to": [{ "resource_group": "rg2" }]
}
  • Das Attribut „requests“ legt die Bedingungen fest, die eine Ressourcengruppe erfüllen muss.
  • Das Attribut „limits“ legt die maximalen Grenzwerte für eine Ressourcengruppe fest.
  • Die Attribute „transfer_from“ und „transfer_to“ beschreiben, aus welchen Ressourcengruppen eine Ressourcengruppe vorzugsweise Ressourcen beziehen sollte und an welche Ressourcengruppen sie Ressourcen übertragen sollte.

Sobald sich die Konfiguration einer Ressourcengruppe ändert, passt Milvus die aktuellen Ressourcen der Abfrageknoten so weit wie möglich an die neue Konfiguration an und stellt sicher, dass alle Ressourcengruppen letztendlich die folgende Bedingung erfüllen:

.requests.nodeNum < nodeNumOfResourceGroup < .limits.nodeNum.

Ausgenommen sind die folgenden Fälle:

  • Wenn die Anzahl der QueryNodes im Milvus-Cluster nicht ausreicht, d. h. NumOfQueryNode < sum(.requests.nodeNum), wird es immer Ressourcengruppen ohne genügend QueryNodes geben.
  • Wenn die Anzahl der QueryNodes im Milvus-Cluster zu hoch ist, d. h. NumOfQueryNode > sum(.limits.nodeNum), werden die redundanten QueryNodes immer zuerst in die __default_resource_group verschoben.

Sollte sich die Anzahl der QueryNodes im Cluster ändern, wird Milvus natürlich kontinuierlich versuchen, sich an die aktuellen Bedingungen anzupassen. Daher können Sie zunächst die Änderungen an der Konfiguration der Ressourcengruppen vornehmen und anschließend die Skalierung der QueryNodes durchführen.

Verwenden Sie die deklarative API zur Verwaltung von Ressourcengruppen

Alle Code-Beispiele auf dieser Seite basieren auf PyMilvus 3.0.1. Aktualisieren Sie Ihre PyMilvus-Installation, bevor Sie sie ausführen.

  1. Erstellen Sie eine Ressourcengruppe.

    Um eine Ressourcengruppe zu erstellen, führen Sie nach dem Herstellen einer Verbindung zu einer Milvus-Instanz den folgenden Befehl aus. Der folgende Codeausschnitt geht davon aus, dass „ default “ der Alias Ihrer Milvus-Verbindung ist.

    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. Ressourcengruppen auflisten.

    Sobald Sie eine Ressourcengruppe erstellt haben, wird diese in der Liste der Ressourcengruppen angezeigt.

    Gehen Sie wie folgt vor, um die Liste der Ressourcengruppen in einer Milvus-Instanz anzuzeigen:

    rgs = milvus_client.list_resource_groups()
    print(f"Resource group list: {rgs}")
    
    # Resource group list: ['__default_resource_group', 'rg']
    
  3. Beschreiben Sie eine Ressourcengruppe.

    Sie können Milvus wie folgt anweisen, eine bestimmte Ressourcengruppe zu beschreiben:

    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. Verschieben Sie Knoten zwischen Ressourcengruppen.

    Möglicherweise stellen Sie fest, dass die beschriebene Ressourcengruppe noch keine Abfrageknoten enthält. Verschieben Sie einige Knoten wie folgt aus der Standard-Ressourcengruppe in die von Ihnen erstellte: Angenommen, es gibt derzeit 1 QueryNode in der __default_resource_group des Clusters, und wir möchten einen Knoten in die erstellte Ressourcengruppe verschieben. update_resource_groups gewährleistet die Atomizität bei mehreren Konfigurationsänderungen, sodass für Milvus keine Zwischenzustände sichtbar sind.

    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. Laden Sie Sammlungen und Partitionen in eine Ressourcengruppe.

    Sobald sich Abfrageknoten in einer Ressourcengruppe befinden, können Sie Sammlungen in diese Ressourcengruppe laden. Der folgende Codeausschnitt geht davon aus, dass bereits eine Sammlung namens „ demo “ existiert.

    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) 
    

    Außerdem können Sie einfach eine Partition in eine Ressourcengruppe laden und deren Replikate auf mehrere Ressourcengruppen verteilen lassen. Im Folgenden wird davon ausgegangen, dass bereits eine Sammlung namens „ Books “ existiert und diese eine Partition namens „ Novels “ enthält.

    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)
    

    Beachten Sie, dass „ _resource_groups “ ein optionaler Parameter ist; wenn Sie ihn nicht angeben, lädt Milvus die Replikate auf die Abfrageknoten in der Standard-Ressourcengruppe.

    Damit Milvus jede Replik einer Sammlung in eine separate Ressourcengruppe lädt, muss die Anzahl der Ressourcengruppen der Anzahl der Repliken entsprechen.

  6. Replikate zwischen Ressourcengruppen verschieben.

    Milvus nutzt Replikate, um einen Lastausgleich zwischen Segmenten zu erreichen, die auf mehrere Abfrageknoten verteilt sind. Sie können bestimmte Replikate einer Sammlung wie folgt von einer Ressourcengruppe in eine andere verschieben:

    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. Eine Ressourcengruppe löschen.

    Sie können eine Ressourcengruppe, die keinen Abfrageknoten enthält (limits.node_num = 0), jederzeit löschen. In dieser Anleitung enthält die Ressourcengruppe „ rg “ derzeit einen Abfrageknoten. Sie müssen zunächst die Konfiguration „ limits.node_num “ der Ressourcengruppe auf Null setzen.

    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}.")
    

Weitere Details finden Sie in den entsprechenden Beispielen in pymilvus

Bewährte Vorgehensweise zur Verwaltung der Cluster-Skalierung

Derzeit kann Milvus in cloud-nativen Umgebungen nicht eigenständig skalieren. Durch die Verwendung der deklarativen Ressourcengruppen-API in Verbindung mit Container-Orchestrierung kann Milvus jedoch auf einfache Weise die Ressourcenisolierung und -verwaltung für QueryNodes erreichen. Hier ist eine bewährte Vorgehensweise für die Verwaltung von QueryNodes in einer Cloud-Umgebung:

  1. Standardmäßig erstellt Milvus eine __default_resource_group. Diese Ressourcengruppe kann nicht gelöscht werden und dient zudem als Standard-Lade-Ressourcengruppe für alle Sammlungen; redundante QueryNodes werden ihr stets zugewiesen. Daher können wir eine „pending“-Ressourcengruppe erstellen, um nicht genutzte QueryNode-Ressourcen aufzunehmen und so zu verhindern, dass diese Ressourcen von der `__default_resource_group` belegt werden.

    Wenn wir zudem die Einschränkung „ sum(.requests.nodeNum) <= queryNodeNum “ strikt durchsetzen, können wir die Zuweisung von QueryNodes im Cluster präzise steuern. Nehmen wir an, es gibt derzeit nur einen QueryNode im Cluster, und initialisieren wir den Cluster. Hier ist ein Beispiel für eine Konfiguration:

    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)
    

    Anhand des obigen Beispielcodes erstellen wir eine Ressourcengruppe namens __pending_nodes, um zusätzliche QueryNodes aufzunehmen. Außerdem erstellen wir zwei benutzerspezifische Ressourcengruppen namens rg1 und rg2. Darüber hinaus stellen wir sicher, dass die andere Ressourcengruppe der Wiederherstellung fehlender oder redundanter QueryNodes aus __pending_nodes Vorrang einräumt.

  2. Horizontale Skalierung des Clusters

    Angenommen, wir haben die folgende Skalierungsfunktion:

    
    def scale_to(node_num: int):
        # scale the querynode number in Milvus into node_num.
        pass
    

    Wir können die API nutzen, um eine bestimmte Ressourcengruppe auf eine festgelegte Anzahl von QueryNodes zu skalieren, ohne dass andere Ressourcengruppen davon betroffen sind.

    # 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. Cluster-Scale-in

    Ebenso können wir Regeln für die Skalierung nach unten festlegen, die der Auswahl von QueryNodes aus der Ressourcengruppe „__pending_nodes“ Vorrang einräumen. Diese Informationen lassen sich über die API „ describe_resource_group “ abrufen. Damit wird das Ziel der Skalierung einer bestimmten Ressourcengruppe nach unten erreicht.

    # 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
    

Wie Ressourcengruppen mit mehreren Replikaten interagieren

  • Die Replikate einer einzelnen Sammlung und die Ressourcengruppen stehen in einer N-zu-N-Beziehung zueinander.
  • Wenn mehrere Replikate einer einzelnen Sammlung in eine Ressourcengruppe geladen werden, werden die QueryNodes dieser Ressourcengruppe gleichmäßig auf die Replikate verteilt, wodurch sichergestellt wird, dass der Unterschied in der Anzahl der QueryNodes, über die jedes Replikat verfügt, 1 nicht überschreitet.

Was kommt als Nächstes?

Um eine mandantenfähige Milvus-Instanz bereitzustellen, lesen Sie Folgendes: