Executando verificação de segurança...
5

Parquet + DuckDB como alternativa ao SQLite em rede SMB

Salve, devs e devas

Vim trazer mais um relato de problema real aqui da empresa, tentando resolver as coisas dentro das limitações que eu tenho.

Hoje eu não posso:

  • Criar um servidor de banco de dados
  • Subir um servidor HTTP para todos os usuários acessarem

Por conta disso, todas as soluções que desenvolvo precisam rodar em um servidor de arquivos SMB, onde cada usuário executa seu próprio processo localmente.

Uso o ambiente .NET para desenvolvimento e, alguns anos atrás, comecei usando Microsoft Access. Funcionava… até certo ponto. Com o tempo, a aplicação começou a ficar lenta. Hoje esse banco tem cerca de 18 mil linhas, ocupa 15 MB e, para rodar, precisa instalar o OLE DB / Jet Engine, que o TI frequentemente esquece de instalar, ainda mais porque versões recentes do Office já não vêm mais com o Access.

Tentativa com SQLite

Para fugir dessa dependência, migrei uma outra aplicação para SQLite, principalmente porque queria usar Dapper e também evitar qualquer instalação extra.

Resultados iniciais:

  • Banco com 4,8 MB
  • Tabelas com 9 mil e 22 mil registros
  • Performance bem melhor no uso individual

Porém, surgiram novos problemas quando o banco ficava no compartilhamento SMB:

  • Se um usuário já estivesse com o banco aberto, outro usuário demorava muito para iniciar
  • Em alguns casos, o primeiro INSERT não era salvo
  • Mesmo habilitando WAL, esse problema ainda acontecia ocasionalmente

Há umas semanas postei um outro problema aqui no TabNews, e algumas pessoas sugeriram o DuckDB como alternativa para esse outro cenário.

Descobrindo uma abordagem diferente

Lendo mais sobre o DuckDB, vi que ele também roda in-process, como o SQLite, mas é otimizado para análise (OLAP). Isso me levou a pesquisar mais e, com ajuda de bastante leitura e perguntas para IA, descobri uma abordagem que resolveu um ponto crítico do meu problema:
escritas concorrentes de múltiplos processos em rede SMB.

A solução acabou sendo usar arquivos Parquet.

Eu sei:

“Parquet não é feito para OLTP.”

Para esse cenario onde não existe muitas transações me parece interessante.

A solução adotada

A ideia foi simples:

  • Cada INSERT, UPDATE ou soft delete gera um arquivo Parquet
  • Nome do arquivo no padrão:
    guid_timestamp.parquet
  • Assim, cada usuário escreve no seu próprio arquivo, sem lock global

Isso gera muitos arquivos pequenos na rede, mas aí entrou uma segunda ideia.

Com a ajuda do meu amigo Cloude, chegamos na seguinte estratégia:

  • Ao iniciar a aplicação, se a pasta tiver mais de 100 arquivos, o processo:
    • Consolida tudo em um único arquivo Parquet
    • Remove os arquivos antigos
    • Reduz drasticamente a quantidade de aberturas de arquivo na rede

Benchmark rápido

Fiz um teste simples:

  • Criei 2.000 arquivos Parquet
  • Consolidei tudo em um único arquivo

Resultados:

  • Abertura antes da consolidação (2k de arquivos): ~2130 ms
  • Abrir o arquivo consolidado (2k registros): ~24 ms

Pelos testes iniciais, parece bem promissor.

Além disso, como o DuckDB carrega os Parquet em memória (:memory:), e pensando em uma aplicação com mais de uma tabela, percebi que é possível:

  • Criar tabelas a partir dos arquivos Parquet
  • Trabalhar de forma relacional
  • Fazer JOINs normalmente

Contexto da empresa

Aqui na empresa não temos um departamento de desenvolvimento.
Eu acabo atuando como um “automatizador” de processos, usando muito Excel, VBA e agora tentando evoluir isso para aplicações mais estruturadas.

O problema da base de dados é sempre um gargalo, principalmente porque:

  • O TI não consegue criar um ambiente de desenvolvimento para a unidade do Brasil
  • A matriz até tem equipe de desenvolvimento, mas muitas necessidades são locais e não se aplicam a todas as unidades

Essa abordagem com Parquet + DuckDB parece uma forma viável de, aos poucos, reduzir a dependência do Excel como ERP improvisado

Resolvi compartilhar essa experiência porque a comunidade aqui é sempre muito técnica e tem me ajudado bastante.

Algumas dúvidas

Algumas perguntas que gostaria de ouvir de quem tem mais experiência:

  1. Alguém aqui já usou Parquet como camada intermediária de escrita nesse estilo (append-only + consolidação)?
  2. Essa abordagem pode virar uma dor de cabeça a médio/longo prazo?
  3. Existe algum risco oculto em usar Parquet dessa forma em rede SMB?
  4. Para esse cenário sem servidor dedicado, existe alguma alternativa melhor que SQLite/DuckDB?
  5. Em termos de integridade e recuperação de falha, vocês enxergam algum ponto crítico que eu deveria tratar desde já?

Obrigado a todos, sempre lembrando qualquer contribuição é muito bem vinda.

Carregando publicação patrocinada...
3

Fala, edsonlcandido! Vi teu post sobre Parquet e lembrei de um troço que pode te interessar: cr-sqlite (github.com/vlcn-io/cr-sqlite).

É uma extensão pro SQLite que bota CRDTs direto nas tabelas. Cada máquina mantém seu banco local, escreve normal, e sincroniza com as outras sem conflito. A resolução é por coluna, automática.

Na prática cada nó roda SQLite com a extensão, faz INSERT/UPDATE como sempre, e de tempos em tempos joga um changeset (SELECT * FROM crsql_changes WHERE db_version > ?) na pasta SMB. Os outros nós leem e aplicam. Não importa a ordem, todo mundo converge pro mesmo estado.

O que tu ganha em cima do Parquet: não precisa mais gerenciar consolidação manual, nomes de arquivo com GUID, nem aquela lógica de compactação quando passa de 100 arquivos. E como continua sendo SQLite, tu tem JOINs, índices, queries relacionais, basicamente o que tu queria do DuckDB sem o overhead de carregar arquivo em memória.

A extensão é em Rust, usa load_extension do SQLite, funciona com .NET sem problema. Overhead de ~2.5x em INSERTs vs SQLite puro, mas com 9-22k registros tu nem vai notar.

Agora, o projeto tem um senão. O mantenedor (Matt Wonlaw) foi pra outra empresa e o ritmo de releases caiu bastante. Última é a v0.16.3 de janeiro. Pro teu cenário eu acho que tá ok, volume baixo, poucos writers, dados que se perder não é o fim do mundo. Mas é bom saber antes de adotar.

1

Vou ver mais informações sobre isso, não tenho muito conhecimento de como carregar essa extensão tanto no código, como para o SQLite studio para testar queries e tal. mas já está anotado aqui. Obrigado pela diaca.
Comunidade aqui é fera demais =).

2

Parabéns pela criatividade na construção de uma solução funcional para um problema com um escopo de infraestrutura tão limitador.

A adoção do Apache Parquet em storage de rede é uma decisão muito boa para leitura. Por ser orientado a colunas, apenas os dados estritamente necessários para a query serão trafegados/baixados pela rede. Ou seja, mesmo consultando um arquivo Parquet de 1GB, não necessariamente você fará a leitura de 1GB de dados na rede.

O principal ponto de atenção nessa abordagem é em relação à escrita. Se você tiver múltiplos dispositivos na rede criando vários arquivos Parquet pequenos de forma recorrente (o famoso small files problem), você provavelmente enfrentará gargalos e perda de performance. Caso isso venha a acontecer, o caminho será aprofundar o entendimento sobre o overhead do protocolo SMB nesse cenário e monitorar o limite de IOPS do disco.

Banco de dados com storage de rede não é loucura. Um exemplo interessante é https://building.nubank.com/pt-br/como-o-nubank-construiu-sua-plataforma-de-logs-interna/.

1

Obrigado pela contribuição, para esse caso dos pequenos arquivos eu criei uma chamada ao iniciar a aplicação que verifica a quantidade de arquivos parquet na pasta e se tiver mais de 100 ele consolida tudo num arquivão só, no meu caso o problema é so a limitação de infra mesmo, pois acredito que vai ter no máximo uns 15 usuários acessando simultaneamente a maioria para leitura, a minha ideia com isso é reduzir os excel de cada setor pois muito deles tem uma inteface comum.
Vi que o DuckDB tem um comportamento similar com arquivos csv, perderia performance mas seria algo mais similar para quem ja salva tudo em excel, abrir no excel seria normal.

2
1

Vou ver sobre esse avro, pois é mais uma possibilidade e como você comentou seobre ser melhor para row based, é exatamente esse meu caso pois o uso dos parquet é somente para essas escritas concorrentes, mas no fundo desenvolvi minha aplicação para ser tabelas relacionais mesmo.
Valeu pela dica.

update:
O DuckDB ainda não escreve arquivos no formato .avro, apenas lê para persitir os dados precisaria savar de alguma outra maneira.

2

Olha não sou a melhor pessoa pra te falar isso, mas posso te dar uma solução diferente, algo que faço com meus bots de Discord que também tive problemas com escrita simultanea. O modo wal acelera por demorar a dar o commit mas ele nao libera multiescrita, o que eu fiz foi criar um processo paralelo que roda uma fila de requisições bloqueantes (as de escritas), então todas as escritas são passadas para essa thread e ela se vira para organizar, rodar a query, commitar etc. Da a sensação que poderia dar delay mas é imperceptível, pelo menos resolve o problema de travar quando dois tentam escrever ao mesmo tempo

Att: esqueci que você não se conectar com um server http, mas tem outras maneiras de fazer os sistemas conversarem entre si sem http. Outra solução que você pode ter é cada computador criar sua cópia do banco, e a cada X tempo ele le os outros bancos na rede smb e atualiza o próprio, algo parecido com a blockchain

1

Para essas estratégias precisaria de uma aplicação para ser a thread de escrita rodando no servidor o q nao daria, não sei como faria essa sincronia, o que fiz com parquet foi meio que isso fazendo as escritas serem todas um arquivo e a mais recente prevalecendo e acho que assim dê bom, e a questao de consolidar depois de 100 arquivos me parece interessante, acredito que com o duckdb seja mais facil manter toda a estrutura e usando o DBeaver para testar as query, obrigado pela contribuição.

1

Hoje eu não posso: Criar um servidor de banco de dados | Subir um servidor HTTP para todos os usuários acessarem

Qual o motivo disso?

tenho curiosidade do porque uma empresa coloca uma limitação dessas

2

Questões de segurança, ninguém quer por a mão no fogo pra uma possível vulnerabilidade através de um sistema que a equipe especializada não toma conta diretamente

1

Eu tambem tenho a mesma duvida rsrsrs,
porém sempre que falo com o TI local aqui da unidade do Brasil, ele fala que o TI global não quer equipes de desenvolvimento locais, que tudo que for desenvolvido precisa ser feito pelo time de desenvolvimento Global (3 pessoas que ficam nos EUA).
Não somos uma empresa que tem o software como produto, somos uma metalurgica de bens de consumo B2B vendemos soluções de engenharia e equipamentos de grande porte para industrias.
Esse tipo de cenario é comum para industria usar o Excel como ERP complementar ao ERP da empresa, tipo cada setor tem suas planilhas então sempre gera um monte de dados duplicados. O TI daqui não permite nem aproveitar o serivodr local de arquivos para subir algum banco de dados, ai sempre bato nessa porta.
Vou criar essa solução usando o DuckDB e vamos ver cenas do proximo capitulo.