paint-brush
Por que você não deve colocar um sistema de arquivos em cima de um armazenamento de objetospor@minio
6,908 leituras
6,908 leituras

Por que você não deve colocar um sistema de arquivos em cima de um armazenamento de objetos

por MinIO7m2023/11/14
Read on Terminal Reader

Muito longo; Para ler

Quando grandes organizações precisam armazenar e acessar oceanos de dados para aprendizagem profunda, IA e outros casos de uso intensivo de dados, o POSIX não tem capacidade ou escalabilidade para atender a essas demandas.
featured image - Por que você não deve colocar um sistema de arquivos em cima de um armazenamento de objetos
MinIO HackerNoon profile picture
0-item
1-item

Ao comprar armazenamento, a ênfase geralmente está na mídia, mas pode ser ainda mais importante considerar também os métodos de acesso. Você precisará levar em consideração os protocolos de armazenamento ao projetar e adquirir infraestrutura, especialmente ao deixar o armazenamento legado para trás para migrar para o armazenamento de objetos nativo da nuvem. No entanto, o armazenamento de objetos depende da API S3 para comunicações, enquanto as cargas de trabalho legadas dependem do POSIX, a interface de sistema operacional portátil que fornece um conjunto de padrões desenvolvidos na década de 1980 para permitir que os aplicativos sejam portáveis entre sistemas operacionais Unix. É provável que a maioria das empresas tenha aplicações em serviço há décadas que foram desenvolvidas para rodar em POSIX. Também é provável que os engenheiros já estejam cientes do fraco desempenho do POSIX.


Dito isto, quando você tem sistemas legados que só podem ingerir dados em um determinado formato ou de uma determinada fonte, suas opções podem ser limitadas e você pode não ter outra escolha a não ser implementar um protocolo desatualizado ou reescrever seu código. Por exemplo, se você só puder ingerir de um disco local com um sistema de arquivos e não com APIs RESTful acessadas pela rede, primeiro deverá disponibilizar esses dados no disco antes que seu aplicativo possa usá-los. No entanto, usar um armazenamento de objetos como sistema de arquivos tem uma série de implicações negativas sérias quando se trata de desempenho, compatibilidade, integridade de dados e segurança.


Vamos demonstrar isso com alguns testes reais usando um pequeno utilitário chamado s3fs-fuse . Este utilitário permite montar um bucket S3 como um sistema de arquivos local. Significa Sistema de Arquivos S3 (Simple Storage Service) - FUSE (Sistema de Arquivos no Espaço do Usuário). É um projeto de código aberto que aproveita a interface FUSE (Filesystem in Userspace) para apresentar uma interface semelhante a um sistema de arquivos para o S3.


Depois que um bucket S3 for montado usando s3fs-fuse , você poderá interagir com o bucket como se fosse um sistema de arquivos local. Isso significa que você pode usar operações regulares de arquivo (como leitura, gravação, movimentação, etc.) em arquivos em seu bucket. Isso parece incrivelmente conveniente e podemos argumentar que simplifica o desenvolvimento de aplicativos. Mas inerentemente o armazenamento de objetos e os sistemas de arquivos têm diferenças fundamentais que afetarão o bucket s3 montado como um sistema de arquivos.


Vamos nos afastar um pouco do utilitário s3fs-fuse para discutir os verdadeiros motivos pelos quais tratar o armazenamento de objetos como um sistema de arquivos está longe de ser o ideal. O problema é muito maior que s3fs-fuse e inclui outros utilitários, como Mountpoint baseado em Rust para Amazon S3 , um cliente de arquivo que traduz chamadas de API do sistema de arquivos local em chamadas de API de objeto S3. A primeira razão é que todos esses utilitários dependem do POSIX para operações do sistema de arquivos. POSIX é ineficiente e nunca foi planejado para trabalhar com arquivos muito grandes na rede.


A velocidade dos sistemas baseados em POSIX diminui à medida que a demanda, especialmente a demanda simultânea, aumenta. Quando grandes organizações precisam armazenar e acessar oceanos de dados para aprendizado profundo, IA e outros casos de uso intensivo de dados, o POSIX não tem capacidade ou escalabilidade para atender a essas demandas. Embora os arrays totalmente Flash tenham mantido o POSIX no jogo, a escalabilidade e as APIs RESTful (as marcas registradas da nuvem) são como a criptonita.


Por causa disso, executar POSIX sobre um armazenamento de objetos não é o ideal. Vamos dar uma olhada em alguns dos motivos:


  1. Desempenho: a interface POSIX FS é inerentemente centrada em IOPS. Eles são tagarelas, caros e difíceis de escalar. A API RESTful S3 resolve isso transformando IOPS em um problema de taxa de transferência. O rendimento é mais fácil e barato de escalar. É por isso que o armazenamento de objetos oferece alto desempenho em grande escala. A camada POSIX sobre S3 não será escalonada porque o POSIX é muito falador para ser executado em uma interface HTTP RESTful.


  2. Semântica: Como as operações de objetos são atômicas e imutáveis, não há como garantir a correção da consistência. Isso significa que você pode perder os dados não confirmados em caso de falha ou ter problemas de corrupção em caso de montagens compartilhadas.


  3. Integridade de dados : gravações ou quaisquer mutações em um arquivo não aparecerão no namespace até que ele seja confirmado. Isso significa que o acesso simultâneo em montagens compartilhadas não verá as modificações. Não é útil para acesso compartilhado.


  4. Controle de acesso: permissões POSIX e ACLs são primitivas e incompatíveis com a maneira da API S3 de lidar com políticas de gerenciamento de identidade e acesso. Não é possível implementar com segurança o gerenciamento de acesso POSIX nas principais APIs S3.


O POSIX também carece da maior parte das funcionalidades que os desenvolvedores adoram no S3, como criptografia em nível de objeto, controle de versão e imutabilidade – elas simplesmente não têm equivalente no mundo POSIX e nada é capaz de traduzi-las.

Pontos problemáticos POSIX

Esses exemplos ilustram a questão e suas implicações. Para começar, usaremos este arquivo CSV que tem aproximadamente 10 GB e 112 linhas.


Nota: assumiremos que o s3fs-fuse já está instalado e você montou um dos buckets do armazenamento de objetos em seu sistema de arquivos. Caso contrário, siga as instruções aqui .


Nestes exemplos, assumiremos que o nome do bucket é test-bucket e o nome do arquivo é taxi-data.csv está no diretório /home/user/ e s3fs-fuse bucket está montado em /home/user/test-bucket/

Operação de cópia

Vamos tentar algo simples primeiro e tentar copiar o arquivo CSV para nosso test-bucket usando comandos mc e registrar o tempo gasto

time mc cp /home/user/taxi-data.csv minio/test-bucket/taxi-data.csv


Isso não deve demorar muito e o arquivo deve ser copiado para nosso bucket. Agora vamos tentar fazer o mesmo com s3fs-fuse

time cp /home/user/taxi-data.csv /home/user/test-bucket/taxi-data.csv


Tempo que levou durante o teste


 real 1m36.056s user 0m14.507s sys 0m31.891s


No meu caso, só consegui copiar o arquivo parcialmente para o bucket e a operação falhou com o seguinte erro


 cp: error writing '/home/user/test-bucket/taxi-data.csv': Input/output error cp: failed to close '/home/user/test-bucket/taxi-data.csv': Input/output error


Depois de várias tentativas, deu certo


 real 5m3.661s user 0m0.053s sys 2m35.234s


Como você pode ver, devido à quantidade de chamadas de API que o utilitário precisa fazer e à sobrecarga geral das operações, o utilitário se torna instável e a maioria das operações nem sequer termina.

Exemplo de pandas

Mostramos um exemplo simples cp , que pode ou não ter sido convincente, porque, convenhamos, você pode pensar que time cp é bastante rudimentar.


Então, para as pessoas que precisam de mais evidências empíricas, vamos escrever um trecho de Python para testar isso. Faremos um exemplo simples do Pandas com s3fs-fuse e o pacote python s3fs e veremos o impacto no desempenho


 import timeit import os import fsspec import s3fs import pandas as pd # Write a dummy CSV file to test-bucket df = pd.DataFrame({"column1": ["new_value1"], "column2": ["new_value2"]}) df.to_csv("s3://test-bucket/data/test-data.csv", index=False) def process_s3(): # add fsspec for pandas to use `s3://` path style and access S3 buckets directly fsspec.config.conf = { "s3": { "key": os.getenv("AWS_ACCESS_KEY_ID", "minioadmin"), "secret": os.getenv("AWS_SECRET_ACCESS_KEY", "minioadmin"), "client_kwargs": { "endpoint_url": os.getenv("S3_ENDPOINT", "https://play.min.io") } } } s3 = s3fs.S3FileSystem() for i in range(100): # Read the existing data print(i) df = pd.read_csv('s3://test-bucket/data/test-data.csv') # Append a new row new_df = pd.concat([df, pd.DataFrame([{"column1": f"value{i}", "column2": f"value{i}"}])], ignore_index=True) # Write the data back to the file new_df.to_csv('s3://test-bucket/data/test-data.csv', index=False) execution_time = timeit.timeit(process_s3, number=1) print(f"Execution time: {execution_time:.2f} seconds")


Tempo gasto durante o teste

 Execution time: 8.54 seconds


Agora vamos tentar o mesmo para s3fs-fuse


 import timeit import pandas as pd # Write a dummy CSV file to test-bucket df = pd.DataFrame({"column1": ["new_value1"], "column2": ["new_value2"]}) df.to_csv("s3://test-bucket/data/test-data.csv", index=False) def process_s3fs(): for i in range(100): # Read the existing data print(i) df = pd.read_csv('/home/user/test-bucket/data/test-data.csv') # Append a new row new_df = pd.concat([df, pd.DataFrame([{"column1": f"value{i}", "column2": f"value{i}"}])], ignore_index=True) # Write the data back to the file new_df.to_csv('/home/user/test-bucket/data/test-data.csv', index=False) execution_time = timeit.timeit(process_s3fs, number=1) print(f"Execution time: {execution_time:.2f} seconds")



Tempo gasto durante o teste

 Execution time: 9.59 seconds


Estes exemplos demonstram leituras e gravações constantes em arquivos S3. Imagine isso realizado simultaneamente por vários clientes – a latência cresce dramaticamente.

Remova a sobrecarga!

Como você pode ver, a diferença entre usar a tradução POSIX para tratar objetos como arquivos e usar a API direta para trabalhar com objetos é noite e dia. Simplesmente não há comparação quando se trata de segurança, desempenho, integridade de dados e compatibilidade. MinIO possui SDKs para integração com quase todas as linguagens de programação populares e pode ser executado em praticamente qualquer plataforma, como Kubernetes, bare metal Linux, contêineres Docker – e muito mais.


MinIO protege objetos com criptografia em repouso e em trânsito, combinada com PBAC para regular o acesso e a codificação de eliminação para proteger a integridade dos dados. Você obterá o melhor desempenho possível, independentemente de onde executar o MinIO, porque ele aproveita o hardware subjacente (consulte Selecionando o melhor hardware para sua implantação do MinIO ) para oferecer o melhor desempenho possível. Comparamos MinIO em 325 GiB/s (349 GB/s) em GETs e 165 GiB/s (177 GB/s) em PUTs com apenas 32 nós de SSDs NVMe prontos para uso.


Simplesmente não há necessidade de um utilitário de sistema de arquivos entre o MinIO e seu aplicativo! Qualquer vantagem que os aplicativos legados possam receber será compensada pelos problemas do POSIX.


Se você tiver alguma dúvida sobre como usar a tradução POSIX para seu aplicativo, entre em contato conosco no Slack !


Também publicado aqui .