🚀 Prova Zilliz Cloud, la versione completamente gestita di Milvus, gratuitamente—sperimenta prestazioni 10 volte più veloci! Prova Ora>>

milvus-logo
LFAI

HomeBlogsInserimento e persistenza dei dati in un database vettoriale

Inserimento e persistenza dei dati in un database vettoriale

  • Engineering
April 06, 2022
Bingyi Sun

Cover image Immagine di copertina

Questo articolo è stato scritto da Bingyi Sun e trascritto da Angela Ni.

Nel precedente post della serie Deep Dive, abbiamo introdotto come vengono elaborati i dati in Milvus, il database vettoriale più avanzato al mondo. In questo articolo continueremo a esaminare i componenti coinvolti nell'inserimento dei dati, illustreremo in dettaglio il modello dei dati e spiegheremo come si ottiene la persistenza dei dati in Milvus.

Vai a:

Riepilogo dell'architettura Milvus

Milvus architecture. Architettura Milvus.

L'SDK invia le richieste di dati al proxy, il portale, tramite il load balancer. Quindi il proxy interagisce con il servizio di coordinamento per scrivere le richieste DDL (linguaggio di definizione dei dati) e DML (linguaggio di manipolazione dei dati) nell'archivio dei messaggi.

I nodi di lavoro, tra cui il nodo di interrogazione, il nodo dei dati e il nodo degli indici, consumano le richieste dall'archivio dei messaggi. In particolare, il nodo di interrogazione è responsabile dell'interrogazione dei dati; il nodo dei dati è responsabile dell'inserimento e della persistenza dei dati; il nodo dell'indice si occupa principalmente della creazione di indici e dell'accelerazione delle query.

Il livello inferiore è costituito dallo storage degli oggetti, che sfrutta principalmente MinIO, S3 e AzureBlob per l'archiviazione di log, binlog delta e file di indice.

Il portale delle richieste di inserimento dati

Proxy in Milvus. Proxy in Milvus.

Proxy funge da portale per le richieste di inserimento dati.

  1. Inizialmente, il proxy accetta le richieste di inserimento dati dagli SDK e le alloca in diversi bucket utilizzando un algoritmo di hash.
  2. Poi il proxy chiede al Data Coord di assegnare i segmenti, l'unità più piccola di Milvus per l'archiviazione dei dati.
  3. In seguito, il proxy inserisce le informazioni dei segmenti richiesti nell'archivio dei messaggi, in modo che non vadano perse.

Coordinamento dati e nodo dati

La funzione principale del data coord è quella di gestire l'allocazione dei canali e dei segmenti, mentre la funzione principale del data node è quella di consumare e persistere i dati inseriti.

Data coord and data node in Milvus. Data coord e data node in Milvus.

Funzione

Il Data Coord svolge le seguenti funzioni:

  • Allocazione dello spazio nei segmentiIl Data coord assegna al proxy lo spazio nei segmenti in crescita, in modo che il proxy possa utilizzare lo spazio libero nei segmenti per inserire i dati.

  • Registrare l'allocazione del segmento e il tempo di scadenza dello spazio allocato nel segmentoLo spazio all'interno di ogni segmento allocato dal data coord non è permanente, pertanto il data coord deve anche tenere un registro del tempo di scadenza di ogni allocazione del segmento.

  • Se il segmento è pieno, il data coord attiva automaticamente ilflushdei dati.

  • Allocazione dei canali ai nodi di datiUna raccolta può avere più canali di dati. Il Data Coord determina quali vcanali sono consumati da quali nodi di dati.

Il nodo dati serve per i seguenti aspetti:

  • Consumo di datiIl nodo dati consuma i dati dai canali allocati da data coord e crea una sequenza per i dati.

  • Persistenza dei datiMemorizza nella cache i dati inseriti e li trasferisce automaticamente su disco quando il volume dei dati raggiunge una certa soglia.

Flusso di lavoro

One vchannel can only be assigned to one data node. Un canale v può essere assegnato a un solo nodo dati.

Come mostrato nell'immagine precedente, la collezione ha quattro vchannel (V1, V2, V3 e V4) e ci sono due nodi dati. È molto probabile che il data coord assegni un nodo dati per consumare i dati da V1 e V2 e l'altro nodo dati da V3 e V4. Un singolo canale v non può essere assegnato a più nodi dati, per evitare la ripetizione del consumo di dati, che altrimenti causerebbe l'inserimento ripetitivo dello stesso batch di dati nello stesso segmento.

Root coord e Time Tick

Root coord gestisce TSO (timestamp Oracle) e pubblica messaggi di time tick a livello globale. Ogni richiesta di inserimento dati ha un timestamp assegnato da root coord. Il Time Tick è la pietra miliare di Milvus, che agisce come un orologio in Milvus e indica in quale punto del tempo si trova il sistema Milvus.

Quando i dati vengono scritti in Milvus, ogni richiesta di inserimento dati porta con sé un timestamp. Durante il consumo dei dati, ogni nodo di dati temporali consuma i dati i cui timestamp sono compresi in un certo intervallo.

An example of data insertion and data consumption based on timestamp. Un esempio di inserimento e consumo di dati in base al timestamp.

L'immagine qui sopra rappresenta il processo di inserimento dei dati. I valori dei timestamp sono rappresentati dai numeri 1,2,6,5,7,8. I dati vengono scritti nel sistema da due proxy: p1 e p2. Durante il consumo dei dati, se l'ora corrente del Time Tick è 5, i nodi di dati possono leggere solo i dati 1 e 2. Poi, durante la seconda lettura, se il tempo corrente del Time Tick diventa 9, i dati 6,7,8 possono essere letti dal nodo dati.

Organizzazione dei dati: raccolta, partizione, shard (canale), segmento

Data organization in Milvus. Organizzazione dei dati in Milvus.

Leggete prima questo articolo per capire il modello dei dati in Milvus e i concetti di collezione, shard, partizione e segmento.

In sintesi, l'unità di dati più grande in Milvus è una raccolta, che può essere paragonata a una tabella in un database relazionale. Una collezione può avere più frammenti (ciascuno corrispondente a un canale) e più partizioni all'interno di ciascun frammento. Come mostrato nell'illustrazione precedente, i canali (shard) sono le barre verticali, mentre le partizioni sono quelle orizzontali. In ogni intersezione si trova il concetto di segmento, l'unità più piccola per l'allocazione dei dati. In Milvus, gli indici sono costruiti sui segmenti. Durante un'interrogazione, il sistema Milvus bilancia anche i carichi delle interrogazioni nei diversi nodi di interrogazione e questo processo è condotto sulla base dell'unità dei segmenti. I segmenti contengono diversi binlog e quando i dati del segmento vengono consumati, viene generato un file binlog.

Segmento

In Milvus esistono tre tipi di segmenti con uno stato diverso: segmento in crescita, segmento sigillato e segmento scaricato.

Segmento in crescita

Un segmento in crescita è un segmento appena creato che può essere assegnato al proxy per l'inserimento dei dati. Lo spazio interno di un segmento può essere utilizzato, allocato o libero.

Three status in a growing segment Tre stati in un segmento in crescita

  • Usato: questa parte di spazio di un segmento in crescita è stata consumata dal nodo dati.
  • Allocato: questa parte di spazio di un segmento in crescita è stata richiesta dal proxy e allocata dal nodo dati. Lo spazio allocato scadrà dopo un certo periodo di tempo.
  • Libero: questa parte di spazio di un segmento in crescita non è stata utilizzata. Il valore dello spazio libero è uguale allo spazio complessivo del segmento sottratto dal valore dello spazio utilizzato e allocato. Pertanto, lo spazio libero di un segmento aumenta man mano che lo spazio allocato scade.

Segmento sigillato

Un segmento sigillato è un segmento chiuso che non può più essere assegnato al proxy per l'inserimento dei dati.

Sealed segment in Milvus Segmento sigillato in Milvus

Un segmento crescente viene sigillato nelle seguenti circostanze:

  • Se lo spazio utilizzato in un segmento in crescita raggiunge il 75% dello spazio totale, il segmento viene sigillato.
  • Flush() viene chiamato manualmente da un utente di Milvus per persistere tutti i dati in una collezione.
  • I segmenti in crescita che non vengono sigillati dopo un lungo periodo di tempo vengono sigillati, poiché troppi segmenti in crescita causano un consumo eccessivo di memoria da parte dei nodi di dati.

Segmento lavato

Un segmento flush è un segmento che è già stato scritto su disco. Il termine flush si riferisce alla memorizzazione dei dati del segmento nella memoria degli oggetti, ai fini della persistenza dei dati. Un segmento può essere flushato solo quando lo spazio allocato in un segmento sigillato scade. Quando si esegue il flush, il segmento sigillato si trasforma in un segmento flush.

Flushed segment in Milvus Segmento flushed in Milvus

Canale

Un canale viene allocato:

  • Quando il nodo dati si avvia o si spegne; oppure
  • Quando lo spazio del segmento allocato viene richiesto da un proxy.

Esistono diverse strategie di allocazione dei canali. Milvus supporta 2 di queste strategie:

  1. Hashing coerente

Consistency hashing in Milvus Hashing coerente in Milvus

È la strategia predefinita di Milvus. Questa strategia sfrutta la tecnica dell'hashing per assegnare a ogni canale una posizione sull'anello, quindi cerca in senso orario il nodo dati più vicino a un canale. Pertanto, nell'illustrazione precedente, il canale 1 è assegnato al nodo dati 2, mentre il canale 2 è assegnato al nodo dati 3.

Tuttavia, un problema di questa strategia è che l'aumento o la diminuzione del numero di nodi dati (ad esempio, l'avvio di un nuovo nodo dati o la chiusura improvvisa di un nodo dati) può influenzare il processo di assegnazione dei canali. Per risolvere questo problema, Data Coord monitora lo stato dei nodi dati tramite etcd, in modo da ricevere una notifica immediata in caso di cambiamenti nello stato dei nodi dati. In seguito, Data Coord determina a quale nodo dati assegnare correttamente i canali.

  1. Bilanciamento del carico

La seconda strategia consiste nell'allocare i canali della stessa collezione a diversi nodi dati, assicurando che i canali siano allocati in modo uniforme. Lo scopo di questa strategia è quello di ottenere il bilanciamento del carico.

Allocazione dei dati: quando e come

The process of data allocation in Milvus Il processo di allocazione dei dati in Milvus

Il processo di allocazione dei dati inizia dal client. Per prima cosa invia al proxy le richieste di inserimento dati con un timestamp t1. Poi il proxy invia una richiesta di allocazione di un segmento al Data Coord.

Una volta ricevuta la richiesta di allocazione del segmento, il data coord controlla lo stato del segmento e lo alloca. Se lo spazio attuale dei segmenti creati è sufficiente per le righe di dati appena inserite, il data coord alloca i segmenti creati. Se invece lo spazio disponibile nei segmenti attuali non è sufficiente, il data coord alloca un nuovo segmento. Il data coord può restituire uno o più segmenti a ogni richiesta. Nel frattempo, il data coord salva anche il segmento allocato nel meta server per la persistenza dei dati.

Successivamente, il data coord restituisce al proxy le informazioni sul segmento allocato (tra cui l'ID del segmento, il numero di righe, il tempo di scadenza t2, ecc. Il proxy invia tali informazioni sul segmento allocato all'archivio dei messaggi, in modo da registrarle correttamente. Si noti che il valore di t1 deve essere inferiore a quello di t2. Il valore predefinito di t2 è di 2.000 millisecondi e può essere modificato configurando il parametro segment.assignmentExpiration nel file data_coord.yaml.

Struttura del file Binlog e persistenza dei dati

Data node flush Nodo dei dati

Il nodo dati si iscrive all'archivio dei messaggi perché le richieste di inserimento dei dati sono conservate nell'archivio dei messaggi e i nodi dati possono quindi consumare i messaggi di inserimento. I nodi dati inseriscono prima le richieste di inserimento in un buffer di inserimento e, man mano che le richieste si accumulano, vengono scaricate nell'object storage dopo aver raggiunto una soglia.

Struttura del file Binlog

Binlog file structure. Struttura del file binlog.

La struttura del file binlog in Milvus è simile a quella di MySQL. Il binlog è utilizzato per due funzioni: il recupero dei dati e la creazione di indici.

Un binlog contiene molti eventi. Ogni evento ha un'intestazione e dei dati.

I metadati, tra cui l'ora di creazione del binlog, l'ID del nodo di scrittura, la lunghezza dell'evento e NextPosition (l'offset dell'evento successivo), ecc. sono scritti nell'intestazione dell'evento.

I dati dell'evento possono essere suddivisi in due parti: fissa e variabile.

File structure of an insert event. Struttura del file di un evento di inserimento.

La parte fissa dei dati dell'evento INSERT_EVENT contiene StartTimestamp, EndTimestamp e reserved.

La parte variabile, invece, contiene i dati inseriti. I dati di inserimento sono sequenziati nel formato del parquet e memorizzati in questo file.

Persistenza dei dati

Se ci sono più colonne nello schema, Milvus memorizza i binlog nelle colonne.

Binlog data persistence. Persistenza dei dati binlog.

Come illustrato nell'immagine precedente, la prima colonna è la chiave primaria binlog. La seconda è la colonna timestamp. Le altre sono le colonne definite nello schema. Il percorso dei file binlog in MinIO è indicato anche nell'immagine precedente.

Informazioni sulla serie Deep Dive

Con l'annuncio ufficiale della disponibilità generale di Milvus 2.0, abbiamo organizzato questa serie di blog Milvus Deep Dive per fornire un'interpretazione approfondita dell'architettura e del codice sorgente di Milvus. Gli argomenti trattati in questa serie di blog includono:

Like the article? Spread the word

Continua a Leggere