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

Cara, antes de tudo, parabéns pelo esforço e pela criatividade. Dá para ver no seu texto que você não está reclamando por reclamar; você está tentando resolver um problema real dentro de limitações bem concretas. Esse tipo de iniciativa tem valor. Muita gente só apontaria o problema. Você foi lá e construiu uma ponte.

Dito isso, preciso te falar uma coisa com respeito e franqueza, porque já vivi algo muito parecido há bastante tempo.

O risco técnico da sua solução é apenas uma parte da história. O risco maior é organizacional. Quando a empresa não te dá ambiente, não te dá arquitetura, não te dá apoio formal, mas aceita que você resolva tudo sozinho com criatividade, acontece uma armadilha: quanto mais competente você for, mais você mascara a fragilidade estrutural da empresa. A automação melhora a rotina, seu chefe gosta, todo mundo passa a depender de você, mas seu cargo não muda, seu salário não muda, e muitas vezes você ainda vira uma ameaça silenciosa para o departamento de TI ou para a burocracia interna.

Pior: você começa resolvendo um gargalo legítimo e, sem perceber, pode acabar virando o “milagreiro oficial” da operação. A empresa economiza estrutura porque você compensa com esforço, improviso e inteligência. Isso parece reconhecimento no começo, mas muitas vezes é só dependência sem valorização real. E dependência sem valorização cobra caro com o tempo.

Falo isso porque já passei por ambiente onde fiz trabalho muito acima do cargo, automatizei, projetei, implantei, segurei rojão, e vi de perto como isso pode virar um tiro no pé. Você melhora tanto o sistema precário que a empresa perde o incentivo de amadurecer. E aí o profissional cresce tecnicamente, mas fica preso num papel pequeno demais para o tamanho do que entrega.

Por isso, eu enxergo duas saídas saudáveis para você.

A primeira é a mais radical, mas às vezes a mais lúcida: pedir demissão e procurar um ambiente onde sua capacidade seja tratada como engenharia, não como remendo permanente.

A segunda, caso você queira continuar aí, é parar de empurrar concorrência de escrita para SMB e assumir uma arquitetura mínima, simples e honesta. Em vez de cada estação disputar arquivo compartilhado, eleja uma máquina ou um processo como master e centralize a escrita nela. Pode ser um pequeno processo .NET auto-hospedado, com uma Web API simples, usando SQLite local, LocalDB ou outro mecanismo local ao host. Os demais clientes só consomem a API. Não precisa IIS, não precisa um “grande servidor”, não precisa nada pomposo. Só precisa parar de tratar filesystem compartilhado como se fosse coordenador transacional.

Se nem isso for politicamente aceitável, então o problema já deixou de ser técnico. Aí é sinal de que a organização quer resultado de sistema sem aceitar as condições mínimas para existir um sistema. Nesse cenário, você corre o risco de passar anos sustentando uma estrutura frágil nas costas.

Seu esforço é bom. Sua criatividade é boa. Seu texto mostra capacidade real. Mas justamente por isso vale o alerta: cuidado para não usar seu talento para consolidar um ambiente que nunca vai te devolver, em estrutura e reconhecimento, o que você está entregando.

Às vezes a solução mais inteligente não é fazer a gambiarra funcionar melhor. É perceber que você está bom demais para ser transformado em infraestrutura invisível. --Dica rápida, bem prática: se você tem um Visual Studio Community e consegue rodar um projeto básico em Blazor na sua máquina, já vale um teste muito simples. Abre esse projeto localmente, descobre o IP da sua estação e tenta acessar pelo navegador de outra máquina da rede usando IP e porta. Se a estação do seu colega não usa proxy no navegador, há uma chance muito alta de isso já funcionar sem IIS, sem SQL Server e sem nenhuma grande cerimônia.

Se abrir no browser, você já provou o ponto principal: a rede provavelmente aceita um pequeno servidor web auto-hospedado dentro do próprio app. A partir daí, você pode evoluir para um servidor seu com Blazor Server, por exemplo, e usar uma API simples por trás. O banco deixa de ser o problema central, porque pode ser qualquer coisa local à máquina host: PostgreSQL, SQL Server, Access, SQLite, o que fizer sentido para o seu cenário e para o que você consegue operar.

Se não abrir no navegador, ainda vale testar com algo mais cru: um client console .NET simples, um GET básico, ou até um curl. Se esse teste conseguir trazer a página inicial ou algum endpoint, então o caminho continua viável e o gargalo pode estar só no browser, proxy ou política local.

O mais importante aqui é que isso te permite sair da lógica de “arquivo compartilhado tentando virar banco” e entrar numa arquitetura mínima, mas muito mais honesta: sua estação vira o host, os outros acessam por IP e porta, e enquanto sua máquina estiver ligada o sistema existe. Isso já serve como MVP real. Depois, se a empresa topar, você dá o próximo passo e sobe isso num servidor web de verdade, em Linux ou container, sem custo alto e com muito mais legitimidade técnica.

Na prática, esse tipo de escassez muitas vezes se resolve quando a solução não exige investimento financeiro. E mesmo que a empresa não abrace de vez, esse experimento já te capacita, te tira da zona do remendo e te aproxima de um modelo mais profissional.

Se até um teste desses for barrado, eu honestamente não perderia energia tentando convencer demais. Usa o que for possível no curto prazo, aproveita o que já construiu como aprendizado e começa a se preparar para sair. Porque daí o problema não é mais técnico, é cultural, e isso raramente melhora.

1

Obrigado por todas as dicas, vou lembrar delas, aqui na empresa é como falei não temos um departamento de desenvolvimento pois a matriz não permite que o TI local tenha então eles já amarram o TI aqui, a ponto de termos so esse servidor de arquivos e um sql server que roda o ERP da empresa, esse SQL so pode rodar o ERP.
Você cita de deixar funcionando enquanto minha maquina estiver ligada para um teste é uma ideia interessante, vou testar num próximo caso.
Um update sobre esse meu uso de parquet na rede por enquanto estou usando somente como leituras de bases de dados separadas que possuímos, tem funcionado bem e rápido, para uma consulta antiga criando uma tabela montada em memória na inicialização com umas 24mil linhas e tem sido bem rápido, inclusive abrindo arquivos SQLite direto no pocket DB então nessa aplicação vi o poder do duckdb.

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.

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

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

Eu uso para meus projetos Aws S3 salvo em parquet e insert as update no ducbdb para facilitar o uso de sql no marimo python. Com isso consigo gerar analises e dashboards muito legais e ainda posso aplicar um modelo LLM em cima dos dados para analise comportamental. Estou gostando muito do duckdb

1

Bom dia, edsonlcandido!

Não daria para utilizar polars e Neo4j?
O polars tem uma grande afinidade com arquivos parquet, então suponho que tem uma maior flexibilidade ao utilizar ele.

Acho que seria algo viável!

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.