O POSIX Realmente Não é Adequado para Armazenamentos de Objetos? Uma Resposta Baseada em Dados

O autor deste post questiona a perspectiva apresentada em um artigo da MinIO, que sugere que o POSIX não é uma opção adequada para armazenamentos de objetos. Ele realizou testes abrangentes envolvendo o MinIO s3fs-fuse e o JuiceFS. Os resultados indicam que o MinIO e o JuiceFS oferecem excelente desempenho enquanto o s3fs-fuse fica aquém. Em cenários de sobrescrita de arquivos pequenos, o FUSE-POSIX do JuiceFS supera outras soluções.

Recentemente, encontrei um artigo no blog da MinIO intitulado “Colocar um Sistema de Arquivos em Cima de um Armazenamento de Objetos é uma Má Ideia. Aqui está o porquê.” O autor utilizou o s3fs-fuse como exemplo para ilustrar os desafios de desempenho encontrados ao acessar dados MinIO usando métodos da Interface de Sistema Operacional Portátil (POSIX), destacando que o desempenho ficou significativamente aquém do acesso direto ao MinIO. O autor atribuiu esses problemas de desempenho a falhas inerentes no POSIX. No entanto, nossa experiência difere um pouco desta conclusão.

POSIX é um padrão útil e amplamente adotado. Desenvolver software seguindo o POSIX garante compatibilidade e portabilidade em diferentes sistemas operacionais. A maioria das aplicações em várias indústrias adere ao padrão POSIX. Com o avanço da computação em nuvem, big data e tecnologias de IA, bem como o aumento do volume de dados armazenados, há uma crescente demanda por soluções de armazenamento elástico como lojas de objetos. Embora lojas de objetos como o MinIO ofereçam SDKs em várias linguagens, muitas aplicações tradicionais têm dificuldade em adaptar seu código para usar APIs de armazenamento de objetos. Isso levou a vários produtos de armazenamento implementando interfaces POSIX sobre lojas de objetos para atender a essa demanda inflexível.

Muitos produtos no mercado, como Ceph, JuiceFS e Weka, implementaram com sucesso interfaces POSIX em lojas de objetos. Essas soluções têm bases de usuários grandes e muitas histórias de sucesso, e se saem bem em termos de desempenho.

Embora seja verdade que o POSIX tem complexidade significativa, os problemas associados não são insuperáveis. Com respeito e vontade de verificar essas alegações, configurei um ambiente de teste, usei os mesmos dados de amostra e métodos de teste descritos no artigo do MinIO e conduzi uma validação.

Produtos Comparados e Objetivos de Teste

Para fornecer uma avaliação abrangente, introduzi o JuiceFS na comparação.

JuiceFS é um sistema de arquivos distribuído de código aberto e nativo de nuvem. Ele utiliza o armazenamento de objetos como camada de armazenamento de dados e depende de um banco de dados separado para armazenar metadados. Oferece vários métodos de acesso, incluindo API POSIX, API S3, Driver CSI, API HDFS e WebDAV, juntamente com mecanismos únicos de divisão de dados, cacheamento e leitura/gravação concorrentes. JuiceFS é um sistema de arquivos, fundamentalmente diferente de ferramentas como s3fs-fuse, que simplesmente convertem de armazenamento de objetos para protocolos POSIX.

Ao introduzir JuiceFS na comparação, pretendi avaliar objetivamente as vantagens e desvantagens de implementar protocolos como POSIX sobre armazenamento de objetos.

I conducted the following two tests on MinIO, JuiceFS, and s3fs-fuse:

  • Escrevendo um arquivo de 10 GB
  • Substituindo arquivos pequenos com Pandas

As três soluções utilizaram uma instância MinIO implantada em servidores separados como armazenamento subjacente. Para as amostras de teste, foi utilizado um arquivo de 10 GB, que era o mesmo arquivo CSV mencionado no artigo do MinIO.

Todas as configurações de ambiente, software, scripts e dados de amostra neste artigo vêm com código completo e instruções para garantir que você possa reproduzir o ambiente e os resultados dos testes.

Configuração do Servidor e Ambiente de Teste

Dois servidores em nuvem configurados identicamente:

  • Sistema: Ubuntu 22.04 x64
  • CPU: 8 núcleos
  • RAM: 16 GB
  • SSD: 500 GB
  • Rede: VPC

Informações para cada servidor:

Server IP Purpose
Server A 172.16.254.18 Deploying the MinIO instance
Server B 172.16.254.19 As the test environment

Preparação do Servidor A

1. Implementei o MinIO no Servidor A usando Docker com os seguintes comandos:

# Crie um diretório dedicado e navegue até ele.
mkdir minio && cd minio

# Crie um arquivo de configuração.
mkdir config
touch config/minio

2. Escrevi as seguintes informações no arquivo config/minio:

MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=abc123abc
MINIO_VOLUMES="/mnt/data"

3. Criei o contêiner MinIO:

sudo docker run -d --name minio \
  -p 9000:9000 \
  -p 9090:9090 \
  -v /mnt/minio-data:/mnt/data \
  -v ./config/minio:/etc/config.env \
  -e "MINIO_CONFIG_ENV_FILE=/etc/config.env" \
  --restart unless-stopped \
  minio/minio server --console-address ":9090"

4. No Console Web do MinIO, previamente criei três buckets:

Bucket name Purpose
test-minio For testing MinIO
test-juicefs For testing JuiceFS
test-s3fs For testing s3fs-fuse

Preparação do Servidor B

1. Baixei o arquivo de amostra de teste de 10 GB.

curl -LO https://data.cityofnewyork.us/api/views/t29m-gskq/rows.csv?accessType=DOWNLOAD

2. Instalei o cliente mc.

mc é um gerenciador de arquivos de linha de comando desenvolvido pelo projeto MinIO. Ele permite operações de leitura e escrita tanto em armazenamento de objetos compatível com S3 quanto em armazenamento local na linha de comando do Linux. O comando mc cp fornece atualizações em tempo real de progresso e velocidade durante a cópia de dados, facilitando a observação de vários testes.

Nota: Para manter a justiça dos testes, todos os três métodos usaram mc para testes de escrita de arquivos.

# Baixe mc.
wget https://dl.min.io/client/mc/release/linux-amd64/mc

# Verifique a versão do mc.
mc -v
mc version RELEASE.2023-09-20T15-22-31Z (commit-id=38b8665e9e8649f98e6162bdb5163172e6ecc187)
Runtime: go1.21.1 linux/amd64

# Instale mc.
sudo install mc /usr/bin

# Defina um alias para MinIO.
mc alias set my http://172.16.254.18:9000 admin abc123abc

3. Baixei s3fs-fuse.

sudo apt install s3fs

# Verifique a versão.
s3fs --version
Amazon Simple Storage Service File System V1.93 (commit:unknown) with OpenSSL

# Defina a chave de acesso do armazenamento de objetos.
echo admin:abc123abc >  ~/.passwd-s3fs

# Modifique as permissões do arquivo de chave.
chmod 600  ~/.passwd-s3fs

# Crie o diretório de montagem.
mkdir mnt-s3fs

# Monte o armazenamento de objetos.
s3fs test-s3fs:/ /root/mnt-s3fs -o url=http://172.16.254.18:9000 -o use_path_request_style

4. Instalei o JuiceFS.

I used the official script to install the latest JuiceFS Community Edition.

# Script de instalação com um clique
curl -sSL https://d.juicefs.com/install | sh -

# Verifique a versão.
juicefs version
juicefs version 1.1.0+2023-09-04.08c4ae6

5. Criei um sistema de arquivos. JuiceFS é um sistema de arquivos que precisa ser criado antes de ser utilizado. Além do armazenamento de objetos, ele requer um banco de dados como mecanismo de metadados. Ele suporta vários bancos de dados. Aqui, utilizei o comumente usado Redis como mecanismo de metadados.

Nota: Instalei o Redis no Servidor A, acessível via 172.16.254.18:6379 sem senha. O processo de instalação é omitido aqui. Você pode consultar a documentação do Redis para mais detalhes.

# Criar o sistema de arquivos.
juicefs format --storage minio \
--bucket http://172.16.254.18:9000/test-juicefs \
--access-key admin \
--secret-key abc123abc \
--trash-days 0 \
redis://172.16.254.18/1 \
myjfs

6. Acessei o JuiceFS usando os métodos mais comuns de API POSIX e S3 e testei seu desempenho.

# Criar diretórios de montagem.
mkdir ~/mnt-juicefs

# Montar o sistema de arquivos no modo POSIX.
juicefs mount redis://172.16.254.18/1 /root/mnt-juicefs

# Acessar o sistema de arquivos usando o método de API S3.
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD=abc123abc
juicefs gateway redis://172.16.254.18/1 0.0.0.0:9000

# Definir um alias para a API S3 do JuiceFS no mc.
mc alias set juicefs http://172.16.254.18:9000 admin abc123abc

Nota: O Gateway do JuiceFS também pode ser implantado no Servidor A ou em qualquer outro servidor acessível pela internet, uma vez que expõe uma API S3 baseada em rede.

Testes e Resultados

Aqui está um resumo rápido dos meus testes e resultados:

Test MinIO S3FS-FUSE JuiceFS
(FUSE)
JuiceFS
(S3 gateway)
Writing a 10 GB file 0m27.651s 3m6.380s 0m28.107s 0m28.091s
Overwriting small files with Pandas 0.83s 0.78s 0.46s 0.96s

Teste 1: Escrevendo um Arquivo de 10 GB

Este teste foi projetado para avaliar o desempenho de escrita de arquivos grandes. Quanto menor o tempo levado, melhor o desempenho. Usei o comando time para medir a duração das operações de escrita, fornecendo três métricas:

  • real: O tempo real desde o início até o fim do comando. Incluiu todos os tempos de espera, como aguardar que operações de E/S sejam concluídas, aguardar trocas de processos e espera por recursos.
  • user: O tempo executado no modo usuário, indicando o tempo de CPU utilizado para executar o código do usuário. Geralmente representava a carga de trabalho computacional do comando.
  • sys: O tempo executado no modo kernel, indicando o tempo de CPU utilizado para executar o código do kernel. Geralmente representava a carga relacionada a chamadas do sistema, como E/S de arquivos e gerenciamento de processos.

MinIO

I ran the following command to perform a copy test:

time mc cp ./2018_Yellow_Taxi_Trip_Data.csv  my/test-minio/

Resultados para escrita de um arquivo de 10 GB diretamente no MinIO:

real    0m27.651s
user    0m10.767s
sys 0m5.439s

s3fs-fuse

I ran the following command to perform a copy test:

time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-s3fs/

Resultados para escrita de um arquivo de 10 GB diretamente no s3fs-fuse:

real 3m6.380s
user 0m0.012s
sys 0m5.459s

Nota: Embora o tempo de escrita tenha sido de 3 minutos e 6 segundos para s3fs-fuse, não houve falhas na escrita, conforme descrito no artigo do MinIO.

JuiceFS

I tested the performance of JuiceFS for large file writes using both the POSIX and S3 API methods:

# Teste de escrita POSIX
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv /root/mnt-juicefs/

# Teste de escrita API S3
time mc cp ./2018_Yellow_Taxi_Trip_Data.csv  juicefs/myjfs/

Resultados para escrita POSIX de um arquivo de 10 GB no JuiceFS:

real    0m28.107s
user    0m0.292s
sys 0m6.930s

Resultados para escrita API S3 de um arquivo de 10 GB no JuiceFS:

real    0m28.091s
user    0m13.643s
sys 0m4.142s

Resumo dos Resultados de Escrita de Arquivos Grandes

A seguinte figura mostra os resultados dos testes:

Large file write results (lower is better)

Os resultados dos testes mostram que tanto a escrita direta no MinIO quanto no JuiceFS tiveram desempenho comparável, concluindo a tarefa em cerca de 30 segundos. Em contraste, s3fs-fuse levou mais de 3 minutos para escrever um arquivo de 10 GB, o que foi aproximadamente seis vezes mais lento do que os dois primeiros.

Ao escrever arquivos grandes, mc utiliza a API Multipart para fazer o upload de arquivos em partes para a interface S3. Por outro lado, s3fs-fuse só pode escrever no POSIX em um único thread. O JuiceFS também divide automaticamente arquivos grandes em partes e as escreve de forma concorrente no MinIO durante gravações sequenciais, garantindo um desempenho equivalente às gravações diretas no MinIO. O S3FS, por sua vez, primeiro escreve em um disco cache em um único thread e depois faz o upload do arquivo em partes para o MinIO, resultando em tempos de gravação mais longos.

Com base na conta de que levou 30 segundos para escrever um arquivo de 10 GB, a velocidade média foi de 333 MB/s. Isso foi limitado pela largura de banda dos SSDs do servidor na nuvem. Esses resultados de teste indicaram que tanto o MinIO quanto o JuiceFS poderiam maximizar a largura de banda do SSD local, e seu desempenho melhoraria com o aprimoramento dos discos de nuvem do servidor e da largura de banda da rede.

Teste 2: Sobrescrever Arquivos Pequenos com Pandas

Este teste avaliou o desempenho dos sistemas de armazenamento de objetos em cenários de sobrescrita de arquivos pequenos. Os scripts de teste para cada software diferiram ligeiramente. Você pode encontrar todo o código do script aqui.

MinIO

I got the test script and ran the test:

# Obtenha o script de teste.
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-minio.py

# Execute o teste.
python3 pandas-minio.py

O resultado foi o seguinte:

Execution time: 0.83 seconds

s3fs-fuse

I got the test script and ran the test:

# Obtenha o script de teste.
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-s3fs.py

# Execute o teste.
python3 pandas-s3fs.py

O resultado do teste foi o seguinte:

Execution time: 0.78 seconds

JuiceFS POSIX

I got the test script and ran the test:

# Obtenha o script de teste.
curl -LO gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-posix.py

# Execute o teste.
python3 pandas-juicefs-posix.py

O resultado do teste foi o seguinte:

Execution time: 0.43 seconds

API S3 do JuiceFS

I got the test script and ran the test:

# Obter o script de teste.
curl -LO https://gist.githubusercontent.com/yuhr123/7acb7e6bb42fb0ff12f3ba64d2cdd7da/raw/30c748e20b56dec642a58f9cccd7ea6e213dab3c/pandas-juicefs-s3api.py

# Executar o teste.
python3 pandas-juicefs-s3api.py

O resultado do teste foi o seguinte:

Execution time: 0.86 seconds

Resumo das Sobreescritas de Arquivos Pequenos do Pandas

A figura a seguir mostra os resultados do teste:

Pandas overwrite results (lower is better)

Neste teste, o JuiceFS FUSE-POSIX demonstrou a velocidade mais rápida, quase o dobro da dos outros soluções. O MinIO, s3fs-fuse e o Gateway S3 do JuiceFS apresentam desempenho semelhante. Do ponto de vista das sobreescritas de arquivos pequenos, a interface POSIX provou ser mais eficiente, oferecendo melhor desempenho do que as interfaces de armazenamento de objetos.

Problemas e Análise

Problema 1: Por que o S3FS foi tão lento?

Análise: A partir dos dados do teste, fica claro que ao escrever o mesmo arquivo de 10 GB, o S3FS levou 3 minutos, enquanto o MinIO e o JuiceFS concluíram a tarefa em cerca de 30 segundos. Essa diferença de desempenho significativa se deve principalmente a implementações técnicas diferentes. Quando s3fs-fuse escreve um arquivo, ele primeiro escreve o arquivo em um arquivo temporário local e depois o carrega no armazenamento de objetos em partes. Se houver espaço em disco local insuficiente, ele faz o upload de forma síncrona. Ele precisa copiar dados entre o disco local e o armazenamento S3. Portanto, arquivos grandes ou um grande número de arquivos resultam em degradação do desempenho.

Além disso, o S3FS depende das capacidades de gerenciamento de metadados do armazenamento de objetos subjacente. Ao lidar com um grande número de arquivos, a interação frequente com o armazenamento de objetos para recuperar metadados tem um impacto significativo na performance. Em termos simples, quanto maior o tamanho do arquivo e a quantidade total de arquivos escritos no S3FS, maior será a sobrecarga de performance proporcional.

Questão 2: Por que o JuiceFS foi mais rápido?

Análise: No teste, tanto o JuiceFS quanto o S3FS utilizaram o FUSE para leitura e escrita. O JuiceFS utilizou plenamente a largura de banda do disco como o MinIO, mas não enfrentou problemas de desempenho como o S3FS.

A resposta está em suas respectivas arquiteturas técnicas. Embora os dados sejam processados através da camada FUSE durante a escrita de arquivos, o JuiceFS usa técnicas de alta concorrência, caching e fragmentação de dados para reduzir a sobrecarga de comunicação entre a camada FUSE e o armazenamento de objetos subjacente. Isso permite que o JuiceFS processe mais solicitações de leitura e escrita de arquivos simultaneamente, reduzindo os tempos de espera e a latência de transmissão.

Além disso, o JuiceFS emprega um banco de dados dedicado (neste caso, Redis) para gerenciar metadados. Ao lidar com um número particularmente grande de arquivos, um mecanismo de metadados independente pode aliviar eficazmente a carga de trabalho, permitindo a localização de arquivos mais rápida.

Conclusão

Os testes acima demonstram que usar o armazenamento de objetos como base e implementar uma interface POSIX em cima disso não necessariamente causa uma perda de desempenho. Independentemente de estarmos escrevendo arquivos grandes ou pequenos, o JuiceFS exibe desempenho comparável a escritas diretas no MinIO, sem qualquer degradação no desempenho do armazenamento de objetos subjacente devido ao acesso POSIX. Além disso, em termos de substituições de tabela Pandas, o desempenho FUSE-POSIX do JuiceFS permanece consistente e até supera o MinIO quase por um fator de dois.

Os resultados dos testes indicam que alguns softwares, como s3fs-fuse, podem sofrer degradação de desempenho ao converter entre interfaces S3 API e POSIX. Embora possa ser uma ferramenta conveniente para acesso temporário a S3, para uso a longo prazo estável e de alto desempenho, é necessário pesquisar e validar cuidadosamente para selecionar soluções mais adequadas.

Para o arquivamento simples de arquivos não estruturados, o uso direto do MinIO ou do armazenamento de objetos em nuvem é uma boa opção. No entanto, para cenários que envolvem armazenamento e processamentos de dados em larga escala, como treinamento de modelos de IA, análise de big data, persistência de dados do Kubernetes e outras operações frequentes de leitura e escrita, o JuiceFS oferece desempenho superior com sua gestão independente de metadados, capacidades de leitura e escrita simultâneas e mecanismos de cache. É uma solução de sistema de arquivos de alto desempenho que vale a pena considerar.

Source:
https://dzone.com/articles/is-posix-really-unsuitable-for-object-stores-a-dat