- Durante el último año, se ha buscado comprender a fondo cómo ejecutar aplicaciones Rails con SQLite de manera rápida y estable
- En ese proceso se aprendieron varias lecciones, y se quieren compartir
- Se explicarán las causas de los problemas y cómo resolverlos
Problemas de SQLite y Rails
- De forma predeterminada, una aplicación Rails con SQLite no queda lista para usarse tal cual
- Con algunos ajustes y afinación, se puede lograr una aplicación rápida y estable
- En Rails 8, el objetivo es que quede lista para producción solo con la configuración por defecto
Aplicación de demostración "Lorem News"
- Se usará una aplicación de demostración llamada "Lorem News" para explicar los problemas y las soluciones
- Esta aplicación es un clon de Hacker News, donde los usuarios pueden escribir publicaciones y comentarios
Pruebas de rendimiento
- Se probó el rendimiento usando el CLI de pruebas de carga
oha y una ruta de benchmarking dentro de la aplicación
- El rendimiento se midió con solicitudes individuales y concurrentes
Problema principal: excepciones SQLITE_BUSY
- SQLite usa bloqueos de escritura para permitir solo una operación de escritura a la vez
- Cuando varias conexiones intentan obtener el bloqueo de escritura al mismo tiempo, ocurre la excepción
SQLITE_BUSY
- Para resolver este problema, se deben usar transacciones inmediatas
Transacciones inmediatas
- De forma predeterminada, SQLite usa el modo de transacción diferida
- Si se usan transacciones inmediatas, se intenta obtener el bloqueo de escritura de inmediato y, si falla, se puede reintentar
- Con la gem
sqlite3-ruby, se puede configurar el modo de transacción predeterminado en modo inmediato
Configuración del timeout
- La configuración de timeout en el archivo
database.yml puede reducir las excepciones SQLITE_BUSY
- Se puede usar la configuración
busy_timeout de SQLite para reintentar el bloqueo de escritura
Problema del GVL (bloqueo global de la VM)
- La gem
sqlite3-ruby no libera el GVL al llamar al código C de SQLite
- Esto perjudica el rendimiento de concurrencia
- Se puede usar
busy_handler para liberar el GVL y mejorar el rendimiento
Reimplementación de busy_timeout
- Se reimplementó
busy_timeout para que todas las consultas se reintenten con la misma frecuencia
- Esto evita que las consultas más antiguas expiren por timeout
Mejora de rendimiento
- Para mejorar el rendimiento, se deben aplicar las siguientes configuraciones
- usar transacciones inmediatas
- configurar el timeout
- usar
busy_handler
- usar el modo WAL (Write-Ahead Logging)
- separar los pools de conexiones de lectura y escritura
Resumen de GN⁺
- Se abordan los problemas de rendimiento de las aplicaciones Rails con SQLite y sus soluciones
- El rendimiento puede mejorar mediante transacciones inmediatas, configuración de timeout, liberación del GVL, uso del modo WAL y separación de los pools de conexiones de lectura y escritura
- Este artículo será muy útil para desarrolladores que usan SQLite y Rails
- Para otros proyectos con funciones similares, se recomiendan PostgreSQL y MySQL
1 comentarios
Comentarios de Hacker News
Introducción al proyecto Litestack de Oldmoe
Agradecimiento por el artículo detallado
Recomendado para quienes trabajan con SQLite
Pregunta sobre un sistema de analítica FOSS
Problema de GVL en la gema sqlite3-ruby
Configuración de un servicio web personal
PRAGMA journal_mode = WALPRAGMA busy_timeout = 5000PRAGMA synchronous = NORMALPRAGMA cache_size = 1000000000PRAGMA foreign_keys = truePRAGMA temp_store = memoryBEGIN IMMEDIATEPregunta sobre Django
Dudas sobre la configuración predeterminada de
busy_timeoutbusy_timeouttiene una demora que castiga a las consultas más antiguasOpinión sobre usar SQLite con Rails
Agradecimiento por resolver problemas de integración con Rails