Armazenamento eficiente de centenas de milhões de arquivos pequenos. Solução Auto-Hospedada



Caro comunidade, este artigo se concentrará no armazenamento e na entrega eficientes de centenas de milhões de arquivos pequenos. Neste estágio, é proposta a solução final para sistemas de arquivos compatíveis com POSIX, com suporte total a bloqueios, incluindo os de cluster e mesmo sem muletas.

Portanto, para esse fim, escrevi meu próprio servidor especializado.
No decorrer desta tarefa, foi possível resolver o problema principal, ao longo do caminho para economizar espaço em disco e RAM, que nosso sistema de arquivos em cluster consumia sem piedade. Na verdade, esse número de arquivos é prejudicial a qualquer sistema de arquivos em cluster.

A ideia é esta:

Em palavras simples, os arquivos pequenos são carregados pelo servidor, eles são salvos diretamente no arquivo morto e também são lidos a partir dele, e arquivos grandes são colocados nas proximidades. Esquema: 1 pasta = 1 arquivo, no total, temos vários milhões de arquivos com arquivos pequenos e não várias centenas de milhões de arquivos. E tudo isso é totalmente implementado, sem scripts e arquivos dobráveis ​​em arquivos tar / zip.

Vou tentar encurtar, peço desculpas antecipadamente se o post será amplo.

Tudo começou com o fato de que eu não conseguia encontrar um servidor adequado no mundo que salvasse os dados recebidos via protocolo HTTP diretamente nos arquivos, para que não houvesse desvantagens inerentes aos arquivos e repositórios de objetos comuns. E o motivo da pesquisa foi um cluster de 10 servidores, que cresceu em larga escala, o Origin, no qual 250.000.000 de arquivos pequenos já haviam se acumulado, e a tendência de crescimento não parava.

Quem não gosta de ler artigos e um pouco de documentação é mais fácil:

aqui e aqui .

Update Removido o nginx da imagem do docker.

E janela de encaixe ao mesmo tempo:
docker run -d --restart=always -e bindaddr=127.0.0.1:9699 \ -e host=localhost -e root=/var/storage -v /var/storage:/var/storage --name wzd \ -p 80:9699 eltaline/wzd 

Seguinte:

Update Na versão 1.1.0, o método de autenticação HTTPS / POST / IP e assim por diante já apareceu.

Se houver muitos arquivos, são necessários recursos significativos e, mais ofensivamente, alguns deles são desperdiçados. Por exemplo, ao usar um sistema de arquivos em cluster (neste caso, MooseFS), um arquivo, independentemente do tamanho real, sempre leva pelo menos 64 KB. Ou seja, para arquivos de 3, 10 ou 30 KB, é necessário 64 KB no disco. Se um quarto de bilhão de arquivos, perdemos 2 a 10 terabytes. Não será possível criar novos arquivos ad infinitum, pois há uma limitação no próprio MooseFS: não mais que 1 bilhão com uma réplica de cada arquivo.

À medida que o número de arquivos aumenta, você precisa de muita RAM para metadados. Despejos freqüentes de grandes metadados também contribuem para o desgaste dos SSDs.

Servidor WZD. Colocamos os discos em ordem.

O servidor está escrito em Go. Primeiro de tudo, eu precisava reduzir o número de arquivos. Como fazer isso? Devido ao arquivamento, mas neste caso sem compactação, já que meus arquivos são sólidos, imagens cortadas. O BoltDB veio em socorro, que ainda precisava ser privado de falhas, isso se reflete na documentação.

No total, em vez de um quarto de bilhão de arquivos, no meu caso, apenas 10 milhões de arquivos Bolt permaneceram. Se eu tivesse a oportunidade de alterar a estrutura atual de preenchimento de arquivos de diretório, seria possível reduzir para cerca de 1 milhão de arquivos.

Todos os arquivos pequenos são compactados nos arquivos Bolt, recebendo automaticamente os nomes dos diretórios em que estão localizados e todos os arquivos grandes permanecem lado a lado com os arquivos; não faz sentido empacotá-los, isso é personalizável. Pequeno - arquivo, grande - deixa inalterado. O servidor trabalha de forma transparente com ambos.

Arquitetura e recursos do servidor wZD.



O servidor está executando Linux, BSD, Solaris e OSX. Testei apenas a arquitetura AMD64 no Linux, mas ela também deve ser adequada para ARM64, PPC64, MIPS64.

Principais recursos:

  • Multithreading;
  • Multi-servidor, oferecendo tolerância a falhas e balanceamento de carga;
  • Transparência máxima para o usuário ou desenvolvedor;
  • Métodos HTTP suportados: GET, HEAD, PUT e DELETE;
  • Gerenciamento do comportamento de leitura e escrita através de cabeçalhos de clientes;
  • Suporte para hosts virtuais personalizáveis;
  • Suporte à integridade dos dados CRC ao escrever / ler;
  • Buffers semi-dinâmicos para consumo mínimo de memória e ajuste ideal do desempenho da rede;
  • Compactação de dados atrasada
  • Além disso, um arquivador wZA multiencadeado é oferecido para migração de arquivos sem interromper o serviço.

Experiência real:

Desenvolvi e testei o servidor e o arquivador de dados ativos por um longo tempo, agora ele opera com êxito em um cluster que inclui 250.000.000 de arquivos pequenos (imagens) localizados em 15.000.000 de diretórios em discos SATA separados. Um cluster de 10 servidores é um servidor Origin instalado atrás de uma rede CDN. Para sua manutenção, são utilizados 2 servidores Nginx + 2 servidores wZD.

Para aqueles que decidem usar esse servidor, faz sentido planejar a estrutura de diretórios antes do uso, se aplicável. Faça imediatamente uma reserva de que o servidor não foi projetado para enviar tudo para o arquivo 1 Bolt.

Teste de desempenho:

Quanto menor o tamanho do arquivo arquivado, mais rapidamente as operações GET e PUT são executadas nele. Compare o tempo total que o cliente HTTP grava nos arquivos regulares e nos arquivos Bolt e também lê. Ele compara o trabalho com arquivos de 32 KB, 256 KB, 1024 KB, 4096 KB e 32768 KB.

Ao trabalhar com arquivos Bolt, a integridade dos dados de cada arquivo é verificada (o CRC é usado), antes da gravação e também após a gravação, a leitura é realizada em tempo real e recontada, isso naturalmente introduz atrasos, mas o principal é a segurança dos dados.

Realizei testes de desempenho em SSDs, pois em discos SATA, os testes não mostram uma diferença clara.

Atualização (v1.1.0), desempenho aprimorado em 5-25%.

Gráficos com base nos resultados do teste:




Como você pode ver, para arquivos pequenos, a diferença no tempo de leitura e gravação entre arquivos arquivados e não arquivados é pequena.

Obteremos uma imagem completamente diferente com o teste de leitura e gravação de arquivos de 32 MB:



A diferença horária entre os arquivos de leitura é de 5 a 25 ms. Com a gravação, as coisas são piores, a diferença é de cerca de 150 ms. Mas, neste caso, não é necessário fazer upload de arquivos grandes, isso simplesmente não faz sentido, eles podem viver separadamente dos arquivos.

* Tecnicamente, este servidor também pode ser usado para tarefas que requerem NoSQL.

Métodos básicos de trabalho com o servidor wZD:

Baixe o arquivo regular:
 curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg 

Fazendo upload de um arquivo para o arquivo morto Bolt (se o parâmetro do servidor fmaxsize não for excedido, o que determina o tamanho máximo do arquivo que pode ser incluído no arquivo morto, se for excedido, o arquivo será carregado como de costume ao lado do arquivo morto):
 curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg 

Download de um arquivo (se houver arquivos com o mesmo nome no disco e no arquivo morto, durante o download, a prioridade padrão será dada ao arquivo descompactado):
 curl -o test.jpg http://localhost/test/test.jpg 

Download de um arquivo do arquivo Bolt (forçado):
 curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg 


Uma descrição de outros métodos está na documentação.

Documentação WZD
Documentação WZA

Até agora, o servidor suporta apenas HTTP; ainda não funciona com HTTPS. O método POST também não é suportado (ainda não foi decidido se é necessário ou não).

Quem se aprofunda no código-fonte encontrará um caramelo lá, nem todo mundo adora, mas eu não vinculei o código principal às funções da estrutura da web, exceto o manipulador de interrupções, para que no futuro eu possa reescrever rapidamente para quase qualquer mecanismo.

ToDo:

  • Desenvolvimento de nosso próprio replicador e distribuidor + geo para a possibilidade de uso em grandes sistemas sem FSs de cluster (tudo para um adulto)
  • A capacidade de reverter completamente os metadados de restauração quando eles são completamente perdidos (se estiver usando um distribuidor)
  • Protocolo nativo para a possibilidade de usar conexões e drivers de rede permanentes para diferentes linguagens de programação
  • Recursos avançados do uso do componente NoSQL
  • Compressões de diferentes tipos (gzip, zstd, snappy) para arquivos ou valores dentro dos arquivos do Bolt e para arquivos comuns
  • Criptografia de tipos diferentes para arquivos ou valores dentro dos arquivos do Bolt e para arquivos comuns
  • Atraso na conversão de vídeo do servidor, incluindo GPU

Isso é tudo, espero que este servidor seja útil para alguém, licença BSD-3, direitos autorais duplos, já que não haveria uma empresa onde eu trabalho, também não escreveria um servidor. Eu sou um desenvolvedor no singular. Ficaria muito grato pelos bugs encontrados e solicitações de recursos.

Source: https://habr.com/ru/post/pt484312/


All Articles