A codificação de eliminação é um método chave de proteção de dados para sistemas de armazenamento distribuído. Esta postagem do blog explica como a codificação de eliminação atende aos requisitos corporativos de proteção de dados e como ela é implementada no MinIO.
A proteção de dados é essencial em qualquer ambiente empresarial porque falhas de hardware, especificamente falhas de unidades, são comuns.
Tradicionalmente, diferentes tipos de tecnologias RAID ou espelhamento/replicação eram usados para fornecer tolerância a falhas de hardware. O espelhamento e a replicação dependem de uma ou mais cópias redundantes completas de dados – essa é uma maneira cara de consumir armazenamento. Tecnologias mais complexas, como RAID5 e RAID6, fornecem a mesma tolerância a falhas e reduzem a sobrecarga de armazenamento. O RAID é uma boa solução para proteção de dados em um único nó, mas falha na escalabilidade devido às demoradas operações de reconstrução necessárias para colocar as unidades com falha novamente on-line.
Muitos sistemas distribuídos usam replicação de três vias para proteção de dados, onde os dados originais são gravados integralmente em três unidades diferentes e qualquer unidade é capaz de reparar ou ler os dados originais. A replicação não é apenas ineficiente em termos de utilização de armazenamento, mas também é operacionalmente ineficiente quando se recupera de falhas. Quando uma unidade falha, o sistema entra no modo somente leitura com desempenho reduzido enquanto copia completamente uma unidade intacta em uma nova unidade para substituir a unidade com falha.
A codificação de eliminação é aplicada à proteção de dados para armazenamento distribuído porque é resiliente e eficiente. Ele divide os arquivos de dados em blocos de dados e paridade e os codifica para que os dados primários sejam recuperáveis mesmo que parte dos dados codificados não esteja disponível. Os sistemas de armazenamento distribuído horizontalmente escaláveis dependem da codificação de eliminação para fornecer proteção de dados, salvando dados codificados em várias unidades e nós. Se uma unidade ou nó falhar ou os dados forem corrompidos, os dados originais poderão ser reconstruídos a partir dos blocos salvos em outras unidades e nós.
A codificação de eliminação é capaz de tolerar o mesmo número de falhas de unidade que outras tecnologias com uma eficiência muito melhor, distribuindo dados entre nós e unidades. Existem muitos algoritmos de codificação de eliminação diferentes, e códigos MDS (Maximum Distance Separable), como Reed-Solomon, alcançam a maior eficiência de armazenamento.
No armazenamento de objetos, a unidade de dados a ser protegida é um objeto. Um objeto pode ser armazenado em n unidades. Se k indica falha potencial, então k < n, e com códigos MDS o sistema pode garantir tolerar n - k falhas de unidade, o que significa que k unidades são suficientes para acessar qualquer objeto.
Considerando um objeto com tamanho de M bytes, o tamanho de cada objeto codificado é M/k (ignorando o tamanho dos metadados). Em comparação com a replicação N-way mostrada acima, com codificação de eliminação configurada para n = 5 e k = 3, um sistema de armazenamento distribuído poderia tolerar a perda de 2 unidades, melhorando ao mesmo tempo a eficiência do armazenamento em 80%. Por exemplo, para 10 PB de replicação de dados seriam necessários mais de 30 PB de armazenamento, enquanto o armazenamento de objetos exigiria de 15 a 20 PB para armazenar e proteger com segurança os mesmos dados usando codificação de eliminação. A codificação de eliminação pode ser configurada para diferentes proporções de dados em relação a blocos de paridade, resultando em uma variedade de eficiência de armazenamento. MinIO mantém uma calculadora de código de eliminação útil para ajudar a determinar os requisitos em seu ambiente.
O MinIO protege os dados com codificação de eliminação inline por objeto (documentação oficial do MinIO para referência ), que é escrita em código assembly para oferecer o mais alto desempenho possível. MinIO utiliza instruções Intel AVX512 para aproveitar totalmente os recursos da CPU do host em vários nós para codificação de eliminação rápida. Uma CPU padrão, unidades NVMe rápidas e uma rede de 100 Gbps suportam a gravação de objetos codificados para eliminação quase na velocidade do fio.
MinIO usa código Reed-Solomon para dividir objetos em dados e blocos de paridade que podem ser configurados para qualquer nível de redundância desejado. Isso significa que em uma configuração de 16 unidades com configuração de 8 paridades, um objeto é distribuído como 8 dados e 8 blocos de paridade. Mesmo se você perder até 7 ((n/2)–1) unidades, seja por paridade ou dados, ainda poderá reconstruir os dados de maneira confiável a partir das unidades restantes. A implementação do MinIO garante que os objetos possam ser lidos ou novos objetos gravados mesmo se vários dispositivos forem perdidos ou indisponíveis.
O MinIO divide objetos em blocos de dados e paridade com base no tamanho do conjunto de eliminação e, em seguida, distribui aleatoriamente e uniformemente os dados e blocos de paridade pelas unidades em um conjunto de modo que cada unidade não contenha mais do que um bloco por objeto. Embora uma unidade possa conter dados e blocos de paridade para vários objetos, um único objeto não possui mais do que um bloco por unidade, desde que haja um número suficiente de unidades no sistema. Para objetos versionados , o MinIO seleciona as mesmas unidades para armazenamento de dados e paridade, mantendo sobreposição zero em qualquer unidade.
A tabela abaixo fornece exemplos de codificação de eliminação no MinIO com dados configuráveis e opções de paridade e taxas de uso de armazenamento que acompanham.
Total de unidades (n) | Unidades de dados (d) | Unidades de paridade (p) | Taxa de uso de armazenamento |
---|---|---|---|
16 | 8 | 8 | 2h00 |
16 | 9 | 7 | 1,79 |
16 | 10 | 6 | 1,60 |
16 | 11 | 5 | 1,45 |
16 | 12 | 4 | 1,34 |
16 | 13 | 3 | 1.23 |
16 | 14 | 2 | 1.14 |
O layout de back-end do MinIO é bastante simples. Cada objeto que chega recebe um conjunto de apagamento. Um conjunto de apagamentos é basicamente um conjunto de unidades, e um cluster consiste em um ou mais conjuntos de apagamentos, determinados pela quantidade total de discos.
Vamos dar uma olhada em um exemplo simples para entender o formato e o layout usado no MinIO.
É importante observar que o formato se refere à proporção entre dados e unidades de paridade - se temos quatro nós com uma única unidade cada ou quatro nós com 100 unidades cada (o MinIO é frequentemente implantado em configurações JBOD densas).
Podemos configurar nossos quatro nós com 100 unidades cada para usar um tamanho de conjunto de apagamento de 16, o padrão. Este é o layout lógico e faz parte das definições dos cálculos de codificação de apagamento. Cada 16 unidades é um conjunto de eliminação composto por 8 unidades de dados e 8 unidades de paridade. Neste caso, o conjunto de apagamento é baseado em 400 drives físicos, divididos igualmente em drives de dados e de paridade, e pode tolerar a perda de até 175 drives.
Os metadados XL do MinIO, escritos atomicamente com o objeto, contêm todas as informações relacionadas a esse objeto. Não há outros metadados no MinIO. As implicações são dramáticas – tudo é independente do objeto, mantendo tudo simples e autodescritivo. Os metadados XL indicam o algoritmo do código de eliminação, por exemplo, dois dados com duas paridades, o tamanho do bloco e a soma de verificação. Ter a soma de verificação gravada junto com os próprios dados permite que o MinIO seja otimizado para memória enquanto suporta dados de streaming, proporcionando uma vantagem clara sobre sistemas que mantêm dados de streaming na memória, depois os gravam no disco e, finalmente, geram uma soma de verificação CRC-32.
Quando um objeto grande, ou seja. maior que 10 MB, for gravado no MinIO, a API S3 o dividirá em um multipart upload. Os tamanhos das peças são determinados pelo cliente durante o upload. O S3 exige que cada parte tenha pelo menos 5 MB (exceto a última parte) e não mais que 5 GB. Um objeto pode ter até 10.000 peças com base na especificação S3. Imagine um objeto com 320 MB. Se este objeto for dividido em 64 partes, o MinIO gravará as partes nos drives como part.1, part.2,...até part.64. As partes são de tamanho aproximadamente igual, por exemplo, o objeto de 320 MB carregado como multiparte seria dividido em 64 partes de 5 MB.
Cada parte que foi carregada é codificada para eliminação na faixa. Part.1 é a primeira parte do objeto que foi carregada e todas as partes são distribuídas horizontalmente nas unidades. Cada parte é composta por seus blocos de dados, blocos de paridade e metadados XL. O MinIO rotaciona as gravações para que o sistema nem sempre grave dados nas mesmas unidades e tenha paridade nas mesmas unidades. Cada objeto é girado de forma independente, permitindo o uso uniforme e eficiente de todas as unidades do cluster, ao mesmo tempo que aumenta a proteção dos dados.
Para recuperar um objeto, o MinIO realiza um cálculo de hash para determinar onde o objeto foi salvo, lê o hash e acessa o conjunto de apagamento e as unidades necessárias. Quando o objeto é lido, existem blocos de dados e de paridade conforme descrito nos metadados XL. O apagamento padrão definido no MinIO é 12 dados e 4 paridades, o que significa que, desde que o MinIO possa ler quaisquer 12 unidades, o objeto poderá ser atendido.
A codificação de eliminação tem diversas vantagens importantes sobre outras tecnologias usadas para proteção de dados em sistemas distribuídos.
Existem vários motivos pelos quais a codificação de eliminação é mais adequada para armazenamento de objetos do que o RAID. A codificação de eliminação MinIO não apenas protege os objetos contra perda de dados no caso de falha de várias unidades e nós, mas o MinIO também protege e cura no nível do objeto. A capacidade de reparar um objeto por vez é uma vantagem dramática sobre o RAID que cura no nível do volume. Um objeto corrompido pode ser restaurado no MinIO em segundos versus horas no RAID. Se uma unidade apresentar defeito e for substituída, o MinIO reconhece a nova unidade, adiciona-a ao conjunto de apagamento e verifica os objetos em todas as unidades. Mais importante ainda, leituras e gravações não afetam umas às outras, permitindo desempenho em escala. Existem implantações MinIO com centenas de bilhões de objetos em petabytes de armazenamento.
A implementação do código de eliminação no MinIO resulta em maior eficiência operacional no datacenter. Ao contrário da replicação, não há reconstrução demorada ou ressincronização de dados entre unidades e nós. Pode parecer trivial, mas mover/copiar objetos pode ser muito caro, e uma unidade de 16 TB que falha e é copiada através da rede do datacenter para outra unidade impõe um enorme imposto ao sistema de armazenamento e à rede.
Se esta postagem do blog despertou sua curiosidade, temos um Erasure Coding Primer mais longo disponível. Baixe o MinIO e comece a proteger os dados com codificação de eliminação hoje mesmo.
Também publicado aqui .