🚀 Essayez Zilliz Cloud, la version entièrement gérée de Milvus, gratuitement—découvrez des performances 10x plus rapides ! Essayez maintenant>>

milvus-logo
LFAI

Préparation

  • Engineering
April 13, 2020
milvus

Dans cet article, nous décrirons principalement comment les données vectorielles sont enregistrées dans la mémoire de Milvus et comment ces enregistrements sont maintenus.

Voici nos principaux objectifs en matière de conception :

  1. L'efficacité de l'importation des données doit être élevée.
  2. Les données peuvent être visualisées dès que possible après leur importation.
  3. Éviter la fragmentation des fichiers de données.

Par conséquent, nous avons créé un tampon de mémoire (tampon d'insertion) pour insérer les données afin de réduire le nombre de changements de contexte des entrées-sorties aléatoires sur le disque et le système d'exploitation afin d'améliorer les performances de l'insertion des données. L'architecture de stockage de la mémoire basée sur MemTable et MemTableFile nous permet de gérer et de sérialiser les données de manière plus pratique. L'état de la mémoire tampon est divisé entre Mutable et Immutable, ce qui permet aux données d'être persistées sur le disque tout en maintenant les services externes disponibles.

Préparation

Lorsque l'utilisateur est prêt à insérer un vecteur dans Milvus, il doit d'abord créer une collection (* Milvus renomme Table en Collection dans la version 0.7.0). La collection est l'unité de base pour l'enregistrement et la recherche de vecteurs dans Milvus.

Chaque collection a un nom unique et certaines propriétés qui peuvent être définies, et les vecteurs sont insérés ou recherchés en fonction du nom de la collection. Lors de la création d'une nouvelle collection, Milvus enregistre les informations relatives à cette collection dans les métadonnées.

Insertion de données

Lorsque l'utilisateur envoie une demande d'insertion de données, les données sont sérialisées et désérialisées pour atteindre le serveur Milvus. Les données sont alors écrites dans la mémoire. L'écriture en mémoire se divise grosso modo en plusieurs étapes :

2-data-insertion-milvus.png 2-data-insertion-milvus.png

  1. Dans MemManager, trouver ou créer une nouvelle MemTable correspondant au nom de la Collection. Chaque MemTable correspond à un tampon de collection en mémoire.
  2. Un MemTable contient un ou plusieurs MemTableFile. Chaque fois que nous créons un nouveau fichier MemTableFile, nous enregistrons simultanément cette information dans le Meta. Nous divisons les MemTableFile en deux états : Mutable et Immuable. Lorsque la taille du fichier MemTableFile atteint le seuil fixé, il devient immuable. Chaque table de mémoire ne peut avoir qu'une seule table de mémoire mutable à écrire à tout moment.
  3. Les données de chaque fichier MemTableFile sont finalement enregistrées dans la mémoire au format du type d'index défini. Le fichier MemTableFile est l'unité de base pour la gestion des données en mémoire.
  4. À tout moment, l'utilisation de la mémoire par les données insérées ne dépassera pas la valeur prédéfinie (insert_buffer_size). En effet, à chaque demande d'insertion de données, MemManager peut facilement calculer la mémoire occupée par le fichier MemTableFile contenu dans chaque MemTable, puis coordonner la demande d'insertion en fonction de la mémoire actuelle.

Grâce à l'architecture multiniveau de MemManager, MemTable et MemTableFile, l'insertion de données peut être mieux gérée et maintenue. Bien entendu, ils peuvent faire bien plus que cela.

Requête en temps quasi réel

Dans Milvus, vous ne devez attendre qu'une seconde au maximum pour que les données insérées passent de la mémoire au disque. L'ensemble de ce processus peut être résumé par l'image suivante :

2-near-real-time-query-milvus.png 2-near-real-time-query-milvus.png

Tout d'abord, les données insérées entrent dans un tampon d'insertion en mémoire. Le tampon passera périodiquement de l'état mutable initial à l'état immuable en préparation de la sérialisation. Ensuite, ces tampons immuables seront périodiquement sérialisés sur le disque par le thread de sérialisation en arrière-plan. Une fois les données placées, les informations relatives à l'ordre sont enregistrées dans les métadonnées. À ce stade, les données peuvent être recherchées !

Nous allons maintenant décrire en détail les étapes de l'image.

Nous connaissons déjà le processus d'insertion des données dans le tampon mutable. L'étape suivante consiste à passer du tampon mutable au tampon immuable :

3-mutable-buffer-immutable-buffer-milvus.png 3-mutable-buffer-immutable-buffer-milvus.png

La file d'attente immuable fournira au thread de sérialisation en arrière-plan l'état immuable et le fichier MemTable prêt à être sérialisé. Chaque table de mémoire gère sa propre file d'attente immuable, et lorsque la taille du seul fichier mutable MemTableFile de la table de mémoire atteint le seuil, il entre dans la file d'attente immuable. Un thread d'arrière-plan responsable de ToImmutable extrait périodiquement tous les MemTableFiles de la file d'attente immuable gérée par MemTable et les envoie dans la file d'attente immuable totale. Il convient de noter que les deux opérations d'écriture de données dans la mémoire et de changement des données dans la mémoire dans un état qui ne peut pas être écrit ne peuvent pas se produire en même temps, et qu'un verrou commun est nécessaire. Toutefois, l'opération ToImmutable est très simple et n'entraîne pratiquement aucun retard, de sorte que l'impact sur les performances des données insérées est minime.

L'étape suivante consiste à sérialiser le fichier MemTableFile dans la file d'attente de sérialisation sur le disque. Cette opération est principalement divisée en trois étapes :

4-serialize-memtablefile-milvus.png 4-serialize-memtablefile-milvus.png

Tout d'abord, le thread de sérialisation en arrière-plan extrait périodiquement les MemTableFile de la file d'attente immuable. Ensuite, ils sont sérialisés en fichiers bruts de taille fixe (Raw TableFiles). Enfin, nous enregistrons ces informations dans les métadonnées. Lorsque nous effectuons une recherche vectorielle, nous interrogeons le fichier TableFile correspondant dans les métadonnées. À partir de là, ces données peuvent être recherchées !

En outre, en fonction de l'ensemble index_file_size, une fois que le thread de sérialisation a terminé un cycle de sérialisation, il fusionne certains TableFiles de taille fixe en un TableFile, et enregistre également ces informations dans les métadonnées. Le fichier TableFile peut alors être indexé. La construction de l'index est également asynchrone. Un autre thread d'arrière-plan responsable de la construction de l'index lira périodiquement le fichier TableFile dans l'état ToIndex des métadonnées afin de procéder à la construction de l'index correspondant.

En fait, vous constaterez qu'avec l'aide de TableFile et des métadonnées, la recherche vectorielle devient plus intuitive et plus pratique. En général, nous devons obtenir les TableFiles correspondant à la collection interrogée à partir des métadonnées, effectuer une recherche dans chaque TableFile et enfin fusionner. Dans cet article, nous ne nous attarderons pas sur la mise en œuvre spécifique de la recherche.

Si vous souhaitez en savoir plus, nous vous invitons à lire notre code source ou nos autres articles techniques sur Milvus !

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

Continuer à Lire