- Au cours de l’année écoulée, l’auteur s’est efforcé de comprendre en profondeur comment exécuter des applications Rails avec SQLite de manière performante et stable
- Il a tiré plusieurs enseignements de ce travail et souhaite les partager
- L’article explique les causes des problèmes et les moyens de les résoudre
Les problèmes de SQLite avec Rails
- Par défaut, une application Rails utilisant SQLite n’est pas prête à l’emploi
- Avec quelques ajustements et réglages fins, il est possible d’obtenir une application performante et stable
- Avec Rails 8, l’objectif est d’atteindre un niveau prêt pour la production avec la configuration par défaut
Application de démonstration « Lorem News »
- L’article s’appuie sur une application de démonstration appelée « Lorem News » pour expliquer les problèmes et leurs solutions
- Cette application est un clone de Hacker News, dans lequel les utilisateurs peuvent publier des billets et des commentaires
Tests de performance
- Les performances sont testées avec le CLI de load testing
oha et une route de benchmarking intégrée à l’application
- Les mesures sont effectuées à la fois sur des requêtes uniques et des requêtes concurrentes
Problème principal : exceptions SQLITE_BUSY
- SQLite utilise un verrou d’écriture afin de n’autoriser qu’une seule opération d’écriture à la fois
- Lorsque plusieurs connexions tentent simultanément d’obtenir ce verrou d’écriture, des exceptions
SQLITE_BUSY se produisent
- Pour résoudre ce problème, il faut utiliser des transactions immédiates
Transactions immédiates
- Par défaut, SQLite utilise le mode de transaction différée
- Avec des transactions immédiates, la tentative d’acquérir le verrou d’écriture se fait immédiatement, et un nouvel essai est possible en cas d’échec
- Le gem
sqlite3-ruby permet de définir le mode de transaction par défaut sur le mode immédiat
Configuration du délai d’attente
- Un réglage de délai d’attente dans le fichier
database.yml permet de réduire les exceptions SQLITE_BUSY
- Le paramètre
busy_timeout de SQLite permet de réessayer l’obtention du verrou d’écriture
Problème du GVL (Global VM Lock)
- Le gem
sqlite3-ruby ne libère pas le GVL lorsqu’il appelle le code C de SQLite
- Cela dégrade les performances en situation de concurrence
- L’utilisation de
busy_handler permet de libérer le GVL et d’améliorer les performances
Réimplémentation de busy_timeout
busy_timeout est réimplémenté afin que toutes les requêtes soient réessayées à la même fréquence
- Cela évite que les requêtes les plus anciennes n’atteignent le délai d’expiration
Améliorations des performances
- Pour améliorer les performances, il faut appliquer les réglages suivants
- utiliser des transactions immédiates
- configurer un délai d’attente
- utiliser
busy_handler
- utiliser le mode WAL (Write-Ahead Logging)
- séparer les pools de connexions en lecture et en écriture
Résumé de GN⁺
- L’article traite des problèmes de performances des applications Rails utilisant SQLite et de leurs solutions
- Les performances peuvent être améliorées grâce aux transactions immédiates, à la configuration du délai d’attente, à la libération du GVL, à l’utilisation du mode WAL et à la séparation des pools de connexions en lecture et en écriture
- Cet article sera très utile aux développeurs qui utilisent SQLite et Rails
- Parmi les autres projets offrant des fonctionnalités similaires, PostgreSQL et MySQL sont recommandés
1 commentaires
Commentaires sur Hacker News
Présentation du projet Litestack par Oldmoe
Merci pour cet article détaillé
Recommandé à toute personne travaillant avec SQLite
Question sur un système d’analyse FOSS
Le problème de GVL dans la gem
sqlite3-rubysqlite3-rubyne libère pas la GVL lors des appels à SQLiteextralitelibère la GVL pendant les opérations bloquantes, est généralement plus rapide et n’a pas de problèmes de concurrenceConfiguration d’un service web personnel
PRAGMA journal_mode = WALPRAGMA busy_timeout = 5000PRAGMA synchronous = NORMALPRAGMA cache_size = 1000000000PRAGMA foreign_keys = truePRAGMA temp_store = memoryBEGIN IMMEDIATEQuestion à propos de Django
Interrogation sur la configuration par défaut de
busy_timeoutbusy_timeoutpar défaut introduit une latence qui pénalise les requêtes anciennesAvis sur l’utilisation de SQLite avec Rails
Merci pour la résolution des problèmes d’intégration avec Rails