- Ao longo do último ano, houve um esforço para compreender profundamente como executar aplicações Rails com SQLite de forma estável e com bom desempenho
- Nesse processo, várias lições foram aprendidas, e a intenção é compartilhá-las
- Serão explicadas as causas dos problemas e como resolvê-los
Problemas entre SQLite e Rails
- Por padrão, uma aplicação Rails usando SQLite não fica pronta para uso imediatamente
- Com alguns ajustes e refinamentos, é possível criar uma aplicação estável e com bom desempenho
- No Rails 8, a meta é fazer com que a configuração padrão já esteja pronta para produção
Aplicação de demonstração "Lorem News"
- Será usada uma aplicação de demonstração chamada "Lorem News" para explicar os problemas e as soluções
- Essa aplicação é um clone do Hacker News, no qual os usuários podem criar postagens e comentários
Testes de desempenho
- O desempenho é testado com a CLI de load testing
oha e com uma rota de benchmarking dentro da aplicação
- O desempenho é medido tanto com requisições individuais quanto com requisições simultâneas
Principal problema: exceção SQLITE_BUSY
- O SQLite usa bloqueio de escrita para permitir apenas uma operação de gravação por vez
- Quando várias conexões tentam obter o bloqueio de escrita ao mesmo tempo, ocorre a exceção
SQLITE_BUSY
- Para resolver esse problema, é necessário usar transações imediatas
Transações imediatas
- Por padrão, o SQLite usa o modo de transação adiada
- Ao usar transações imediatas, a tentativa de obter o bloqueio de escrita acontece imediatamente, e em caso de falha é possível tentar novamente
- Com a gem
sqlite3-ruby, é possível definir o modo padrão de transação como imediato
Configuração de timeout
- A configuração de timeout no arquivo
database.yml pode reduzir as exceções SQLITE_BUSY
- É possível usar a configuração
busy_timeout do SQLite para tentar novamente ao disputar o bloqueio de escrita
Problema do GVL (Global VM Lock)
- A gem
sqlite3-ruby não libera o GVL ao chamar o código C do SQLite
- Isso prejudica o desempenho em cenários concorrentes
- É possível usar
busy_handler para liberar o GVL e melhorar o desempenho
Reimplementação de busy_timeout
busy_timeout foi reimplementado para que todas as consultas façam novas tentativas com a mesma frequência
- Isso evita que consultas mais antigas estourem o timeout
Melhorias de desempenho
- Para melhorar o desempenho, é preciso aplicar as seguintes configurações
- usar transações imediatas
- configurar timeout
- usar
busy_handler
- usar o modo WAL (Write-Ahead Logging)
- separar os pools de conexão de leitura e escrita
Resumo do GN⁺
- O texto aborda problemas de desempenho em aplicações Rails com SQLite e suas soluções
- O desempenho pode ser melhorado com transações imediatas, configuração de timeout, liberação do GVL, uso do modo WAL e separação dos pools de conexão de leitura e escrita
- Este artigo será muito útil para desenvolvedores que usam SQLite e Rails
- Outros projetos recomendados com funcionalidades semelhantes são PostgreSQL e MySQL
1 comentários
Comentários do Hacker News
Apresentação do projeto Litestack, do Oldmoe
Agradecimento pelo artigo detalhado
Recomendação para quem trabalha com SQLite
Pergunta sobre um sistema FOSS de analytics
Problema de GVL na gem sqlite3-ruby
Configuração de um serviço web pessoal
PRAGMA journal_mode = WALPRAGMA busy_timeout = 5000PRAGMA synchronous = NORMALPRAGMA cache_size = 1000000000PRAGMA foreign_keys = truePRAGMA temp_store = memoryBEGIN IMMEDIATEPergunta sobre Django
Dúvida sobre a configuração padrão de
busy_timeoutbusy_timeouttem um atraso que penaliza consultas mais antigasOpinião sobre usar SQLite com Rails
Agradecimento por resolver problemas de integração com Rails