Comment Milvus planifie les tâches de requête
Dans cet article, nous verrons comment Milvus planifie les tâches de requête. Nous parlerons également des problèmes, des solutions et des orientations futures pour la mise en œuvre de la planification de Milvus.
Contexte
Nous savons, d’après Managing Data in Massive-Scale Vector Search Engine, que la recherche de similarité vectorielle est mise en œuvre par la distance entre deux vecteurs dans un espace à haute dimension. L’objectif de la recherche vectorielle est de trouver K vecteurs qui sont les plus proches du vecteur cible.
Il existe de nombreuses façons de mesurer la distance vectorielle, comme la distance euclidienne :
Distance euclidienne.
où x et y sont deux vecteurs. n est la dimension des vecteurs.
Afin de trouver les K vecteurs les plus proches dans un jeu de données, la distance euclidienne doit être calculée entre le vecteur cible et tous les vecteurs du jeu de données à rechercher. Ensuite, les vecteurs sont triés par distance afin d’obtenir les K vecteurs les plus proches. Le travail de calcul est directement proportionnel à la taille du jeu de données. Plus le jeu de données est grand, plus une requête nécessite de travail de calcul. Un GPU, spécialisé dans le traitement graphique, dispose justement de nombreux cœurs pour fournir la puissance de calcul requise. Ainsi, la prise en charge multi-GPU est également prise en compte lors de l’implémentation de Milvus.
Concepts de base
Bloc de données(TableFile)
Pour améliorer la prise en charge de la recherche de données à très grande échelle, nous avons optimisé le stockage des données de Milvus. Milvus divise les données d’une table par taille en plusieurs blocs de données. Lors de la recherche vectorielle, Milvus recherche les vecteurs dans chaque bloc de données et fusionne les résultats. Une opération de recherche vectorielle consiste en N opérations de recherche vectorielle indépendantes (N est le nombre de blocs de données) et N-1 opérations de fusion des résultats.
File d’attente des tâches(TaskTable)
Chaque Resource possède un tableau de tâches, qui enregistre les tâches appartenant à la Resource. Chaque tâche possède différents états, notamment Start, Loading, Loaded, Executing et Executed. Le Loader et l’Executor d’un dispositif de calcul partagent la même file d’attente des tâches.
Planification des requêtes
Planification des requêtes.
- Lorsque le serveur Milvus démarre, Milvus lance le GpuResource correspondant via les paramètres
gpu_resource_configdans le fichier de configurationserver_config.yaml. DiskResource et CpuResource ne peuvent toujours pas être modifiés dansserver_config.yaml. GpuResource est la combinaison desearch_resourcesetbuild_index_resourceset est désigné par{gpu0, gpu1}dans l’exemple suivant :
Exemple de code.
Exemple.
- Milvus reçoit une requête. Les métadonnées de la table sont stockées dans une base de données externe, qui est SQLite ou MySQl pour un hôte unique et MySQL pour le distribué. Après avoir reçu une requête de recherche, Milvus vérifie si la table existe et si la dimension est cohérente. Ensuite, Milvus lit la liste TableFile de la table.
Milvus lit la liste tablefile.
- Milvus crée une SearchTask. Comme le calcul de chaque TableFile est effectué indépendamment, Milvus crée une SearchTask pour chaque TableFile. En tant qu’unité de base de la planification des tâches, une SearchTask contient les vecteurs cibles, les paramètres de recherche et les noms de fichiers de TableFile.
Créateur de tâche de liste de fichiers de table.
- Milvus choisit un dispositif de calcul. Le dispositif sur lequel une SearchTask effectue le calcul dépend du temps d’achèvement estimé pour chaque dispositif. Le temps d’achèvement estimé spécifie l’intervalle estimé entre l’heure actuelle et l’heure estimée à laquelle le calcul s’achève.
Par exemple, lorsqu’un bloc de données d’une SearchTask est chargé dans la mémoire CPU, la SearchTask suivante attend dans la file d’attente des tâches de calcul CPU et la file d’attente des tâches de calcul GPU est inactive. Le temps d’achèvement estimé pour le CPU est égal à la somme du coût temporel estimé de la SearchTask précédente et de la SearchTask actuelle. Le temps d’achèvement estimé pour un GPU est égal à la somme du temps nécessaire au chargement des blocs de données dans le GPU et du coût temporel estimé de la SearchTask actuelle. Le temps d’achèvement estimé pour une SearchTask dans une Resource est égal au temps d’exécution moyen de toutes les SearchTasks dans la Resource. Milvus choisit ensuite un appareil avec le plus faible temps d’achèvement estimé et assigne la SearchTask à l’appareil.
Ici, nous supposons que le temps d’achèvement estimé pour GPU1 est plus court.
Temps d’achèvement estimé plus court pour GPU1.
Milvus ajoute SearchTask à la file d’attente des tâches de DiskResource.
Milvus déplace SearchTask vers la file d’attente des tâches de CpuResource. Le thread de chargement dans CpuResource charge chaque tâche depuis la file d’attente des tâches de manière séquentielle. CpuResource lit les blocs de données correspondants dans la mémoire CPU.
Milvus déplace SearchTask vers GpuResource. Le thread de chargement dans GpuResource copie les données de la mémoire CPU vers la mémoire GPU. GpuResource lit les blocs de données correspondants dans la mémoire GPU.
Milvus exécute SearchTask dans GpuResource. Comme le résultat d’une SearchTask est relativement petit, il est directement renvoyé à la mémoire CPU.
Planificateur.
- Milvus fusionne le résultat de SearchTask avec le résultat de recherche global.
Milvus fusionne les résultats des tâches de recherche.
Une fois toutes les SearchTasks terminées, Milvus renvoie le résultat de recherche global au client.
Construction d’index
La construction d’index est essentiellement identique au processus de recherche, sans le processus de fusion. Nous n’en parlerons pas en détail.
Optimisation des performances
Cache
Comme mentionné précédemment, les blocs de données doivent être chargés dans les dispositifs de stockage correspondants, tels que la mémoire CPU ou la mémoire GPU, avant le calcul. Pour éviter le chargement répétitif des données, Milvus introduit un cache LRU (Least Recently Used). Lorsque le cache est plein, les nouveaux blocs de données évincent les anciens blocs de données. Vous pouvez personnaliser la taille du cache via le fichier de configuration en fonction de la taille actuelle de la mémoire. Un grand cache pour stocker les données de recherche est recommandé afin d’économiser efficacement le temps de chargement des données et d’améliorer les performances de recherche.
Chevauchement du chargement des données et du calcul
Le cache ne peut pas satisfaire nos besoins en matière de meilleures performances de recherche. Les données doivent être rechargées lorsque la mémoire est insuffisante ou que la taille du jeu de données est trop grande. Nous devons réduire l’effet du chargement des données sur les performances de recherche. Le chargement des données, qu’il s’agisse du disque vers la mémoire CPU ou de la mémoire CPU vers la mémoire GPU, relève des opérations d’E/S et nécessite à peine du travail de calcul de la part des processeurs. Nous envisageons donc d’effectuer le chargement des données et le calcul en parallèle pour une meilleure utilisation des ressources.
Nous divisons le calcul sur un bloc de données en 3 étapes (chargement du disque vers la mémoire CPU, calcul CPU, fusion des résultats) ou 4 étapes (chargement du disque vers la mémoire CPU, chargement de la mémoire CPU vers la mémoire GPU, calcul GPU et récupération des résultats, et fusion des résultats). Prenons le calcul en 3 étapes comme exemple : nous pouvons lancer 3 threads responsables des 3 étapes afin de fonctionner comme un pipeline d’instructions. Comme les ensembles de résultats sont généralement petits, la fusion des résultats ne prend pas beaucoup de temps. Dans certains cas, le chevauchement du chargement des données et du calcul peut réduire le temps de recherche de moitié.
Chargement chevauchant séquentiel Milvus.
Problèmes et solutions
Vitesses de transmission différentes
Auparavant, Milvus utilisait la stratégie Round Robin pour la planification des tâches multi-GPU. Cette stratégie fonctionnait parfaitement sur notre serveur à 4 GPU et les performances de recherche étaient 4 fois meilleures. Cependant, pour nos hôtes à 2 GPU, les performances n’étaient pas 2 fois meilleures. Nous avons mené quelques expériences et découvert que la vitesse de copie des données pour un GPU était de 11 Go/s. Cependant, pour un autre GPU, elle était de 3 Go/s. Après avoir consulté la documentation de la carte mère, nous avons confirmé que la carte mère était connectée à un GPU via PCIe x16 et à un autre GPU via PCIe x4. Autrement dit, ces GPU ont des vitesses de copie différentes. Plus tard, nous avons ajouté le temps de copie pour mesurer le périphérique optimal pour chaque SearchTask.
Travaux futurs
Environnement matériel avec une complexité accrue
Dans des conditions réelles, l’environnement matériel peut être plus complexe. Pour les environnements matériels avec plusieurs CPU, de la mémoire avec architecture NUMA, NVLink et NVSwitch, la communication entre CPU/GPU apporte de nombreuses possibilités d’optimisation.
Optimisation des requêtes
Pendant l’expérimentation, nous avons découvert certaines possibilités d’amélioration des performances. Par exemple, lorsque le serveur reçoit plusieurs requêtes pour la même table, les requêtes peuvent être fusionnées sous certaines conditions. En utilisant la localité des données, nous pouvons améliorer les performances. Ces optimisations seront mises en œuvre dans notre futur développement. Maintenant, nous savons déjà comment les requêtes sont planifiées et exécutées dans le scénario mono-hôte, multi-GPU. Nous continuerons à présenter davantage de mécanismes internes de Milvus dans les prochains articles.
Continuer à lire

A Few Notes from Databricks Data + AI Summit 2026: Why the Data Layer Matters Again
James Luan shares notes from Databricks Data + AI Summit 2026 on why production AI is pushing the data layer back to the center of infrastructure.

Our Journey to 35K+ GitHub Stars: The Real Story of Building Milvus from Scratch
Join us in celebrating Milvus, the vector database that hit 35.5K stars on GitHub. Discover our story and how we’re making AI solutions easier for developers.

Zilliz Cloud Introduces Advanced BYOC-I Solution for Ultimate Enterprise Data Sovereignty
Explore Zilliz Cloud BYOC-I, the solution that balances AI innovation with data control, enabling secure deployments in finance, healthcare, and education sectors.



