🚀 Experimente o Zilliz Cloud, o Milvus totalmente gerenciado, gratuitamente—experimente um desempenho 10x mais rápido! Experimente Agora>>

milvus-logo
LFAI
  • Home
  • Blog
  • Como são processados os dados numa base de dados vetorial?

Como são processados os dados numa base de dados vetorial?

  • Engineering
March 28, 2022
Zhenshan Cao

Cover image Imagem da capa

Este artigo foi escrito por Zhenshan Cao e transcrito por Angela Ni.

Nos dois posts anteriores desta série de blogues, já abordámos a arquitetura do sistema Milvus, a base de dados vetorial mais avançada do mundo, e o seu Python SDK e API.

Este post tem como principal objetivo ajudá-lo a compreender como os dados são processados no Milvus, aprofundando o sistema Milvus e examinando a interação entre os componentes de processamento de dados.

Alguns recursos úteis antes de começar estão listados abaixo. Recomendamos que os leia primeiro para compreender melhor o tópico deste post.

Interface MsgStream

A interface MsgStream é crucial para o processamento de dados em Milvus. Quando Start() é chamado, a corrotina em segundo plano escreve dados no broker de registo ou lê dados a partir daí. Quando Close() é chamado, a corrotina pára.

MsgStream interface Interface MsgStream

O MsgStream pode servir como produtor e consumidor. A interface AsProducer(channels []string) define o MsgStream como um produtor, enquanto a AsConsumer(channels []string, subNamestring)o define como um consumidor. O parâmetro channels é partilhado em ambas as interfaces e é utilizado para definir os canais (físicos) em que os dados devem ser escritos ou lidos.

O número de fragmentos de uma coleção pode ser especificado quando a coleção é criada. Cada fragmento corresponde a um canal virtual (vchannel). Portanto, uma coleção pode ter vários vchannels. O Milvus atribui a cada vchannel do broker de log um canal físico (pchannel).

Each virtual channel/shard corresponds to a physical channel. Cada canal virtual/shard corresponde a um canal físico.

Produce() A interface MsgStream é responsável pela escrita de dados nos pchannels do log broker. Os dados podem ser escritos de duas formas:

  • Escrita única: as entidades são escritas em diferentes shards (vchannel) pelos valores de hash das chaves primárias. Em seguida, essas entidades fluem para os pchannels correspondentes no broker de registo.
  • Escrita de difusão: as entidades são escritas em todos os pchannels especificados pelo parâmetro channels.

Consume() é um tipo de API de bloqueio. Se não houver dados disponíveis no canal p especificado, a corrotina será bloqueada quando Consume() for chamado na interface MsgStream. Por outro lado, Chan() é uma API não bloqueante, o que significa que a corrotina lê e processa dados apenas se existirem dados no canal p especificado. Caso contrário, a corrotina pode processar outras tarefas e não será bloqueada quando não houver dados disponíveis.

Seek() é um método de recuperação de falhas. Quando um novo nó é iniciado, o registo de consumo de dados pode ser obtido e o consumo de dados pode ser retomado a partir do ponto em que foi interrompido, chamando Seek().

Escrita de dados

Os dados escritos em diferentes vchannels (fragmentos) podem ser mensagens de inserção ou de eliminação. Estes vchannels podem também ser designados por DmChannels (canais de manipulação de dados).

Colecções diferentes podem partilhar os mesmos pchannels no corretor de registo. Uma coleção pode ter vários shards e, por conseguinte, vários vchannels correspondentes. Consequentemente, as entidades da mesma coleção fluem para vários canais p correspondentes no corretor de registos. Como resultado, a vantagem da partilha de pchannels é um aumento do volume de produção possibilitado pela elevada concorrência do corretor de registos.

Quando uma coleção é criada, não só é especificado o número de fragmentos, como também é decidido o mapeamento entre vchannels e pchannels no broker de registo.

Write path in Milvus Caminho de escrita no Milvus

Como se pode ver na ilustração acima, no percurso de escrita, os proxies escrevem dados no corretor de registos através da interface AsProducer() do MsgStream. Em seguida, os nós de dados consomem os dados e depois convertem e armazenam os dados consumidos no armazenamento de objectos. O caminho de armazenamento é um tipo de meta-informação que será registada no etcd pelos coordenadores de dados.

Diagrama de fluxo

Uma vez que diferentes colecções podem partilhar os mesmos pchannels no corretor de registos, ao consumir dados, os nós de dados ou os nós de consulta têm de avaliar a que coleção pertencem os dados num pchannel. Para resolver este problema, introduzimos o flowgraph no Milvus. É principalmente responsável pela filtragem de dados num pchannel partilhado por IDs de coleção. Assim, podemos dizer que cada flowgraph lida com o fluxo de dados num shard (vchannel) correspondente numa coleção.

Flowgraph in write path Fluxógrafo no caminho de escrita

Criação de MsgStream

Ao escrever dados, o objeto MsgStream é criado nos dois cenários seguintes:

  • Quando o proxy recebe um pedido de inserção de dados, tenta primeiro obter o mapeamento entre vchannels e pchannels através do coordenador raiz (root coord). Em seguida, o proxy cria um objeto MsgStream.

Scenario 1 Cenário 1

  • Quando o nó de dados é iniciado e lê as meta-informações dos canais no etcd, é criado o objeto MsgStream.

Scenario 2 Cenário 2

Ler dados

Read path in Milvus Caminho de leitura em Milvus

O fluxo de trabalho geral da leitura de dados é ilustrado na imagem acima. Os pedidos de consulta são transmitidos através do canal DqRequestChannel para os nós de consulta. Os nós de consulta executam as tarefas de consulta em paralelo. Os resultados da consulta dos nós de consulta passam pelo gRPC e o proxy agrega os resultados e devolve-os ao cliente.

Para analisar mais detalhadamente o processo de leitura de dados, podemos ver que o proxy escreve os pedidos de consulta no DqRequestChannel. Os nós de consulta consomem então a mensagem subscrevendo o DqRequestChannel. Cada mensagem no DqRequestChannel é difundida para que todos os nós de consulta subscritos possam receber a mensagem.

Quando os nós de consulta recebem pedidos de consulta, efectuam uma consulta local tanto dos dados em lote armazenados em segmentos selados como dos dados em fluxo contínuo que são inseridos dinamicamente no Milvus e armazenados em segmentos crescentes. Posteriormente, os nós de consulta precisam de agregar os resultados da consulta em segmentos selados e em crescimento. Estes resultados agregados são transmitidos ao proxy através do gRPC.

O proxy recolhe todos os resultados de vários nós de consulta e, em seguida, agrega-os para obter os resultados finais. Em seguida, o proxy devolve os resultados finais da consulta ao cliente. Uma vez que cada pedido de consulta e os resultados de consulta correspondentes são identificados pelo mesmo requestID único, o proxy pode descobrir que resultados de consulta correspondem a que pedido de consulta.

Grafo de fluxo

Flowgraph in read path Diagrama de fluxo no caminho de leitura

À semelhança do caminho de escrita, os fluxogramas também são introduzidos no caminho de leitura. O Milvus implementa a arquitetura Lambda unificada, que integra o processamento dos dados incrementais e históricos. Por conseguinte, os nós de consulta também precisam de obter dados de fluxo contínuo em tempo real. Do mesmo modo, os fluxogramas no percurso de leitura filtram e diferenciam os dados de diferentes colecções.

Criação de MsgStream

Creating MsgStream object in read path Criação do objeto MsgStream no percurso de leitura

Ao ler os dados, o objeto MsgStream é criado no cenário seguinte:

  • No Milvus, os dados só podem ser lidos se forem carregados. Quando o proxy recebe um pedido de carregamento de dados, envia-o para o coordenador de consultas, que decide a forma de atribuir fragmentos a diferentes nós de consulta. A informação de atribuição (ou seja, os nomes dos vchannels e o mapeamento entre os vchannels e os pchannels correspondentes) é enviada aos nós de consulta através de uma chamada de método ou RPC (chamada de procedimento remoto). Subsequentemente, os nós de consulta criam os objectos MsgStream correspondentes para consumir os dados.

Operações DDL

DDL significa linguagem de definição de dados. As operações DDL em metadados podem ser categorizadas em pedidos de escrita e pedidos de leitura. No entanto, estes dois tipos de pedidos são tratados da mesma forma durante o processamento de metadados.

Os pedidos de leitura de metadados incluem:

  • Esquema de coleção de consultas
  • Informações de indexação de consultas e muito mais

Os pedidos de escrita incluem:

  • Criar uma coleção
  • Eliminar uma coleção
  • Criar um índice
  • Eliminar um índice E mais

Os pedidos DDL são enviados para o proxy a partir do cliente, e o proxy transmite esses pedidos pela ordem recebida ao coordenador raiz, que atribui um carimbo de data/hora a cada pedido DDL e efectua verificações dinâmicas dos pedidos. O proxy trata cada pedido de forma serial, ou seja, um pedido DDL de cada vez. O proxy não processará o pedido seguinte até concluir o processamento do pedido anterior e receber os resultados da coordenada de raiz.

DDL operations. Operações DDL.

Conforme mostrado na ilustração acima, há K solicitações DDL na fila de tarefas da coordenada raiz. As solicitações DDL na fila de tarefas são organizadas na ordem em que são recebidas pelo coordenador raiz. Assim, ddl1 é o primeiro enviado à coord raiz e ddlK é o último deste lote. O coordenador raiz processa os pedidos um a um na ordem temporal.

Num sistema distribuído, a comunicação entre os proxies e a coordenada de raiz é activada por gRPC. O coordenador raiz mantém um registo do valor máximo do carimbo de data/hora das tarefas executadas para garantir que todos os pedidos DDL são processados por ordem temporal.

Suponha que existam dois proxies independentes, proxy 1 e proxy 2. Ambos enviam pedidos DDL para a mesma coordenada raiz. No entanto, um problema é que os pedidos anteriores não são necessariamente enviados para a coordenada de raiz antes dos pedidos recebidos por outro proxy mais tarde. Por exemplo, na imagem acima, quando DDL_K-1 é enviado para a coordenada de raiz a partir do proxy 1, DDL_K do proxy 2 já foi aceite e executado pela coordenada de raiz. Conforme registado pelo coordenador raiz, o valor máximo do carimbo de data/hora das tarefas executadas neste momento é K. Assim, para não interromper a ordem temporal, o pedido DDL_K-1 será rejeitado pela fila de tarefas do coordenador de raiz. No entanto, se o proxy 2 enviar o pedido DDL_K+5 para a coordenada raiz neste momento, o pedido será aceite na fila de tarefas e será executado mais tarde de acordo com o seu valor de carimbo de data/hora.

Indexação

Construção de um índice

Ao receber pedidos de construção de índices do cliente, o proxy começa por efetuar verificações estáticas nos pedidos e envia-os para a coordenada de raiz. Em seguida, a coord raiz persiste esses pedidos de construção de índice no meta-armazenamento (etcd) e envia os pedidos para o coordenador do índice (coord índice).

Building an index. Construção de um índice.

Como ilustrado acima, quando o coordenador de índice recebe pedidos de construção de índice do coordenador de raiz, primeiro persiste a tarefa no etcd para meta store. O estado inicial da tarefa de construção de índice é Unissued. O coordenador de índices mantém um registo da carga de tarefas de cada nó de índice e envia as tarefas de entrada para um nó de índice menos carregado. Após a conclusão da tarefa, o nó de índice escreve o estado da tarefa, Finished ou Failed no meta armazenamento, que é o etcd em Milvus. Em seguida, o coordenador do índice compreenderá se a tarefa de construção do índice foi bem sucedida ou falhou, consultando o etcd. Se a tarefa falhar devido a recursos limitados do sistema ou à desistência do nó de índice, o coordenador do índice irá reativar todo o processo e atribuir a mesma tarefa a outro nó de índice.

Eliminação de um índice

Para além disso, o coordenador de índices também é responsável pelos pedidos de eliminação de índices.

Dropping an index. Eliminar um índice.

Quando o coordenador da raiz recebe um pedido de eliminação de um índice do cliente, primeiro marca o índice como "eliminado" e devolve o resultado ao cliente enquanto notifica o coordenador do índice. Em seguida, o coordenador do índice filtra todas as tarefas de indexação com o endereço IndexID e as tarefas que correspondem à condição são eliminadas.

A corrotina em segundo plano do coordenador de índices eliminará gradualmente todas as tarefas de indexação marcadas como "eliminadas" do armazenamento de objectos (MinIO e S3). Este processo envolve a interface recycleIndexFiles. Quando todos os arquivos de índice correspondentes são excluídos, as meta informações das tarefas de indexação excluídas são removidas do meta armazenamento (etcd).

Sobre a série Deep Dive

Com o anúncio oficial da disponibilidade geral do Milvus 2.0, orquestrámos esta série de blogues Milvus Deep Dive para fornecer uma interpretação aprofundada da arquitetura e do código-fonte do Milvus. Os tópicos abordados nesta série de blogues incluem:

Try Managed Milvus for Free

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

Get Started

Like the article? Spread the word

Continue Lendo