lobste.rs migra do MariaDB para SQLite
(lobste.rs)- Depois de migrar do MariaDB para o SQLite, o lobste.rs lidou de forma estável até mesmo com o pico de tráfego de segunda-feira, confirmando menor uso de CPU e memória e uma sensação de resposta mais rápida
- Ao desligar o VPS separado do MariaDB, o custo de VPS cairá pela metade, e a tarefa de migração iniciada em 2019 também será concluída
- No primeiro deploy, todo o tráfego somente leitura levou todas as CPUs a 100%, causando um rollback; depois de corrigir duas varreduras completas de tabela em tabelas grandes e um problema de N+1, o novo deploy foi bem-sucedido
- Foi necessário implementar
regexp,ifestddevcomo funções definidas pelo usuário no SQLite, além de resolver restrições de compatibilidade como a falta de suporte a unsigned bigint e oNOCASE, que trata apenas ASCII - Para trocar o banco de dados subjacente sem acessar o banco de produção, são necessários dados de teste em escala realista, uma suíte de testes, checklists de deploy e rollback e colaboração próxima
Das discussões de 2019 à migração para SQLite
- A discussão sobre a migração começou em 2019 na issue #539
- Na época, o MySQL foi sugerido como alternativa considerando a compatibilidade com o MariaDB, mas já havia uma discussão em andamento sobre migração para PostgreSQL
- Em 2025, Rahul mencionou a aquisição do MariaDB pela K1, dando continuidade à discussão detalhada sobre a migração para PostgreSQL
- Em fevereiro, Rahul perguntou se o lobsters poderia rodar em SQLite, e a participação no projeto se intensificou a partir de junho de 2025
- O primeiro PR, de agosto de 2025, teve o trabalho interrompido e depois foi fechado pelo GitHub como um PR antigo, sem possibilidade de reabertura
- O segundo PR incluiu testes de desempenho, um script próprio de migração entre bancos e depuração relacionada à integridade dos dados
- Como nenhum dos scripts existentes de conversão MariaDB/MySQL→SQLite atendia aos requisitos, foi escrito um script separado
Falha no primeiro deploy e correção dos gargalos de desempenho
- O primeiro deploy, em 21 de fevereiro, foi feito com uma checklist de deploy, mas logo após o deploy apenas o tráfego em modo somente leitura levou todas as CPUs a 100%
- Como não foi possível encontrar a causa, foi feito um rollback
- Sem acesso ao banco de produção, era difícil reproduzir antecipadamente o problema real de desempenho
- Dois dias após a falha, foi aberto o terceiro e último PR, corrigindo problemas relacionados à busca e adicionando um script de geração de dados em massa para criar localmente um conjunto com metade do tamanho dos dados reais do lobsters
- Gerar os dados levou uma semana
- O gargalo do primeiro deploy foi causado por varreduras completas de tabela provocadas por duas queries em tabelas grandes e por um problema separado de N+1
- Foram incorporadas a alteração 1, a alteração 2 e a alteração 3 para resolver isso
- Na manhã do dia do deploy, foram adicionados logs de queries lentas para permitir acompanhar problemas adicionais de desempenho
Resultado do novo deploy e redução de custos operacionais
- No segundo deploy, em 11 de julho, as checklists de deploy e rollback foram preparadas novamente; após a migração, o site continuou operando normalmente, e o uso de CPU e memória também se manteve estável
- Monitorando as métricas do site e o IRC, os problemas reportados foram tratados imediatamente com a correção 1 e a correção 2
- Não houve problemas no pico de tráfego de segunda-feira, e foram confirmados menor uso de CPU e memória e uma sensação de resposta mais rápida
- Ao encerrar o VPS do MariaDB, o custo de VPS cairá pela metade, e a issue de migração também será fechada
Restrições do SQLite que diferiam do MariaDB
- Usando o suporte a funções definidas pelo usuário (UDF) da gem do SQLite, foram implementadas no SQLite as funções
regexp,if,stddev, que não existiam nele- Isso evitou adicionar workarounds excessivos para a migração SQL
- Como o SQLite não dá suporte a unsigned bigint, usado em alguns IDs no MariaDB, eles foram alterados para bigint
- As regras de ordenação também são mais limitadas do que no MariaDB
- No MariaDB era usado
utf8mb4_general_ci, mas no SQLite foi aplicadoNOCASE NOCASEnão oferece suporte a case folding completo de UTF e processa apenas caracteres ASCII
- No MariaDB era usado
- Para tabelas de busca de texto completo do SQLite, o formato recomendado, e não o padrão, Contentless-Delete Tables, é adequado
- As configurações PRAGMA padrão do Rails funcionam corretamente no lobsters
- Como as migrações de banco de dados variam por DB, as migrações existentes foram movidas para o diretório old_migrations, mantendo o
db:migratefuncionando
- Como as migrações de banco de dados variam por DB, as migrações existentes foram movidas para o diretório old_migrations, mantendo o
Lições de testes e colaboração
- Na base de código do lobsters, foram encontrados o parser de busca e o hack heinous_inline_partials, que acelera a renderização
- Graças à suíte de testes, foi possível verificar a correção da migração para SQLite sem testes manuais em grande escala
- A comunicação fluida entre os participantes foi determinante para o sucesso da migração
- Substituir o banco de dados subjacente sem acesso ao banco de produção foi extremamente difícil
- Se o mesmo trabalho fosse feito novamente, seria necessário preparar com antecedência uma escala de dados realista
- Se tivesse sido possível configurar os testes para falhar quando ocorresse uma varredura completa de tabela, o problema de desempenho do primeiro deploy poderia ter sido detectado antes
- É necessária uma ferramenta que permita criar facilmente um dataset semelhante ao de produção, sem precisar escrevê-lo manualmente ou esperar uma semana
1 comentários
Opiniões no Lobste.rs
@thomas0 cuidou minuciosamente da migração em larga escala, @355E3B ajudou no planejamento e na operação, e, graças aos colaboradores relacionados à #539 e ao #lobsters, até o período em modo somente leitura foi divertido
Originalmente, a #539 previa PostgreSQL, mas a pessoa que se ofereceu para fazer o trabalho usou SQLite, e a escolha foi pelo SQLite para evitar uma solução maior e mais complexa do que a demanda esperada. PostgreSQL costuma ser a escolha padrão, mas há o ônus de operar, ajustar e manter um serviço separado
Surpreendentemente, após a migração, o uso de CPU e RAM diminuiu, e os gráficos detalhados estão no fim da #539
Fico surpreso sempre que vejo as configurações padrão do SQLite. Seria bom haver um modo para novos projetos que viesse por padrão com WAL, chaves estrangeiras,
synchronous=NORMALetc., e parece que ainda há outros valores padrão que poderiam ser melhoradosTenho curiosidade sobre a estratégia de backup do banco de dados SQLite. Gostaria de saber se usam alguma ferramenta como litestream ou outro método
Tenho curiosidade sobre como o lobste.rs lida com operações de atualização
O SQLite já tem a função iif, mas operar funções definidas pelo usuário nessa mesma área também é algo interessante
Eu achava que o SQLite não oferecia concorrência no mesmo nível do PostgreSQL ou MySQL, mas, lendo a documentação de visão geral, devo entender que agora ele pode ser usado por vários processos, embora o lobste.rs precise rodar em um único servidor?
Também gostaria de saber se os processos são sincronizados internamente pelo SQLite por meio de memória compartilhada ou algo como
mmap, permitindo apenas uma escrita simultânea e várias leituras, e se as escritas pendentes aguardam sua vez em uma filaPara escritas em espera, parece ser usado um mecanismo de aguardar por um curto período e tentar novamente, em vez de uma fila explícita em memória compartilhada. Não tenho certeza se é totalmente impossível usar SQLite em várias máquinas, mas a abordagem simples de compartilhar o arquivo via NFS é explicitamente desaconselhada, então entender como servidor único é uma aproximação razoável, e hoje em dia uma única máquina já consegue lidar com uma escala considerável
busy_timeoutfuncione As referências são https://fractaledmind.github.io/2024/04/… , https://kerkour.com/sqlite-for-servers e https://www.sqlite.org/lang_transaction.html#immediate ; veja a seçãoSQLITE_BUSYno segundo link e o terceiro link para mais detalhesÉ um upgrade impressionante, com detalhes muito bem organizados em PRs, issues e Gists. Fico curioso se essa mudança gerou diferenças funcionais, como na busca do site, e qual é o tamanho em disco do arquivo SQLite atual
Lembro de terem dito em algum lugar que o tamanho do arquivo SQLite é 3,8 GB