Je mise tout sur SQLite côté serveur
(fly.io)- Ben Johnson, le créateur de BoltDB (une base clé-valeur embarquée), développe désormais Litestream chez FlyIO
- La structure la plus courante d’une application full stack est le modèle n-tiers : serveur d’applications + serveur de base de données
→ Dans cette architecture, SQLite n’était utilisé que pour les tests unitaires, mais il peut désormais parfaitement servir de couche de données et de persistance - Litestream est un projet open source qui rend SQLite utilisable dans des applications full stack grâce à la réplication
Brève histoire des bases de données applicatives
-
50 ans, ce n’est pas si long, mais la manière dont les logiciels gèrent les données a énormément changé
→ Dans les années 1970, il y a eu les « règles de Codd » qui ont défini la base de données relationnelle
→ Toutes les données sont dans des tables, avec CRUD, schéma, langage SQL, etc.
→ Dans les années 1980 et 1990, les bases SQL comme Oracle/DB2/Postgres/MySQL ont explosé en nombre
→ Les bases XML des années 2000 n’étaient pas très bonnes, tandis que d’excellentes bases orientées colonnes apparaissaient à la même période
→ Dans les années 2010, de grands projets open source de bases distribuées ont été lancés, et aujourd’hui n’importe qui peut monter un cluster et interroger des données à l’échelle du téraoctet -
À mesure que les bases de données évoluaient, les stratégies pour les connecter aux applications ont elles aussi progressé
→ Depuis Codd, on a séparé en tiers
→ D’abord le tier base de données
→ Puis le tier de cache avec memcached et Redis
→ Puis le tier des tâches en arrière-plan (Sidekiq), le tier de routage (PgBouncer), le tier de distribution, etc.
→ Beaucoup de tutoriels parlent comme s’il n’y avait que 3 tiers, mais comme on ne sait jamais combien il y en aura, on parle ici de modèle « n-tiers » -
En 50 ans, on a aussi vu le CPU, la mémoire et le disque devenir des centaines de fois plus rapides et moins chers
→ Le mot qui définit réellement l’innovation dans les bases de données des années 2010, c’est le « big data »
→ Mais avec l’amélioration du matériel, ce concept est devenu plus difficile à soutenir dans les années 2020
→ En 1996, gérer une base de 1 Go était énorme ; en 2022, cela tourne très bien sur un laptop ou même sur unet3.micro -
Quand on réfléchit à de nouvelles architectures de base de données, on est hypnotisé par les limites de scalabilité
→ Si on ne peut pas traiter des pétaoctets, ou au minimum des téraoctets, on n’entre même pas dans la conversation
→ Pourtant, la plupart des applications, même en cas de succès, ne verront jamais des volumes de données de l’ordre du téraoctet
→ On utilise un marteau-piqueur pour enfoncer un clou
La douce sortie de SQLite
- Il existe une base de données qui reflète très bien cette tendance
- C’est l’une des bases SQL les plus connues au monde, le format d’archivage officiel de la Bibliothèque du Congrès des États-Unis, réputée pour sa fiabilité, pour une suite de tests d’une taille difficile à imaginer, et pour ses excellentes performances
- À ce niveau, il n’est même plus nécessaire de dire son nom… mais pour ceux au fond qui lèvent la main… il s’agit bien de SQLite
- SQLite est une base embarquée. Dans une architecture en tiers classique, elle n’existe pas en tant que tier séparé : c’est simplement une bibliothèque liée au processus de votre serveur applicatif
→ Une « application mono-processus » qui tourne seule, sans dépendre d’un autre serveur
- Comme je construis des bases de données, ce type d’application m’intéresse
- J’ai créé BoltDB, une base clé/valeur embarquée bien connue dans l’écosystème Go
- BoltDB est stable et offre des performances dignes d’une petite voiture jouet dopée au nitro, comme on l’attend d’une base in-process
- Mais BoltDB a des limites
→ Le schéma étant défini dans le code Go, les migrations de base sont difficiles. Il faut construire soi-même les outils. Il n’y a même pas de REPL
- Si vous êtes prudent, ce type de base peut offrir des performances extraordinaires
- Mais pour un usage généraliste, vous n’aurez sans doute pas envie d’exploiter ce genre de base
- Je me suis demandé ce qu’il fallait faire pour rendre BoltDB utilisable dans davantage d’applications, et ma conclusion a été : « SQLite a précisément été conçu pour ça »
- SQLite a bien sûr aussi des contraintes. La plus grande est qu’une application mono-processus a un SPOF (Single Point of Failure) : si vous perdez le serveur, vous perdez aussi la base. Ce n’est pas un défaut de SQLite, c’est son design
Entrée en scène de Litestream
- Il y a deux grandes raisons pour lesquelles beaucoup de gens n’utilisent pas SQLite par défaut
→ D’abord, la résilience face aux erreurs de stockage
→ Ensuite, la concurrence quand on monte en charge - Litestream a quelque chose à dire sur ces deux sujets
-
Litestream fonctionne en contrôlant le journal du mode WAL (Write Ahead Log) de SQLite
-
En mode WAL, les opérations d’écriture sont ajoutées à un fichier journal séparé du fichier principal de la base SQLite
-
Les lecteurs consultent à la fois le fichier WAL et la base principale pour satisfaire leurs requêtes
-
En temps normal, SQLite exécute automatiquement un checkpoint des pages du WAL vers la base principale
-
Litestream s’intercale à cette étape en ouvrant une transaction de lecture infinie qui empêche le checkpoint automatique, capture et réplique lui-même les mises à jour du WAL, puis déclenche ses propres checkpoints
La chose la plus importante à comprendre avec Litestream, c’est que c’est juste SQLite. L’application utilise SQLite standard ; Litestream n’ajoute pas de dépendance, n’analyse pas les requêtes et ne joue pas le rôle de proxy. Il exploite simplement les mécanismes de journalisation et de concurrence déjà présents dans SQLite. Dans la plupart des cas, votre code peut même ignorer l’existence de Litestream
- Cela peut sembler complexe, mais en pratique c’est extrêmement simple. En l’utilisant, on se rend compte que ça « just works »
$ litestream replicate fruits.db s3://my-bukkit:9000/fruits.db
$ litestream restore -o fruits-replica.db s3://my-bukkit:9000/fruits.db
- En général, les gens s’en servent pour répliquer une base SQLite et la stocker sur S3
- Cela apporte un gros avantage opérationnel. Votre base devient résiliente et peut être déplacée ou migrée facilement
- Mais Litestream permet d’aller plus loin
- Dans la prochaine version, la réplication en temps réel entre bases SQLite sera possible, ce qui permettra de mettre en place des read replicas distribués et une base leader en écriture
→ Les read replicas pourront capter les écritures et les rediriger vers le leader
→ Comme beaucoup d’applications sont surtout orientées lecture, cette configuration pourra fournir à l’application une base extensible à l’échelle mondiale
Vous devriez prendre cette option plus au sérieux : utiliser SQLite comme base applicative
- L’un de mes premiers métiers dans l’IT a été DBA Oracle au début des années 2000
- J’ai passé énormément de temps à lire des livres et de la documentation pour apprendre Oracle
- Le manuel d’administration faisait près de mille pages, et ce n’était qu’un document parmi des centaines
- À l’époque, apprendre quoi faire pour optimiser les requêtes ou améliorer les écritures faisait vraiment la différence
- Les disques durs lisaient quelques dizaines de mégaoctets par seconde, donc utiliser un meilleur index pouvait transformer une requête de 5 minutes en requête de 30 secondes
- Mais l’optimisation des bases de données devient de moins en moins importante pour les applications classiques
- Avec une base de 1 Go, un disque NVMe peut tout charger en mémoire en moins d’une seconde
- J’aime l’optimisation SQL, mais pour beaucoup de développeurs applicatifs, c’est devenu une compétence en voie de disparition
- Même une requête mal optimisée peut s’exécuter en moins d’une seconde dans beaucoup de bases
- Le Postgres moderne est un miracle. J’ai beaucoup appris en lisant ce code pendant des années
- Optimiseur de requêtes, politiques de sécurité au niveau ligne, six types d’index, etc.
- Si vous avez besoin de ces fonctionnalités, elles sont importantes ; mais dans la majorité des cas, ce n’est pas le cas
- Et si vous n’avez pas besoin de ces fonctionnalités de Postgres, elles ont quand même un coût en responsabilité
- Même sans utiliser plusieurs comptes, il faut configurer l’authentification par hôte et ouvrir le firewall
- Plus il y a de fonctionnalités, plus il y a de documentation, et il devient difficile de réellement comprendre le logiciel que vous exploitez
- La documentation de Postgre14 approche les 3 000 pages
- SQLite offre un sous-ensemble des fonctionnalités de Postgres. Mais cela couvre généralement 99,9 % de ce que je veux
- Excellent support SQL, fonctions de fenêtre, CTE, recherche plein texte, support JSON, etc.
- Et si une fonctionnalité manque, comme les données sont à côté de mon application, le coût pour les récupérer et les traiter reste faible
- En revanche, les problèmes vraiment complexes à résoudre ne le sont pas par les fonctionnalités centrales d’une base de données
- À la place, je veux surtout optimiser deux choses : la latence et l’expérience développeur
- Une bonne raison de considérer SQLite sérieusement, c’est donc la simplicité d’exploitation
- On peut arrêter de concevoir une couche base de données et consacrer son temps à écrire du code applicatif
- Mais il y a encore un autre problème
La lumière est beaucoup trop lente : The Light is Too Damn Slow
- On commence à buter sur des limites théoriques. Dans le vide, la lumière parcourt 186 miles en 1 milliseconde (l’équivalent d’un aller-retour entre Philadelphie et New York)
- Et c’est encore plus lent quand on ajoute des switches réseau, des firewalls et des couches de protocole applicatif
- Dans une même région AWS, le surcoût de latence d’une requête Postgres peut aller jusqu’à 1 milliseconde
- Cela ne veut pas dire que Postgres est lent, mais qu’on atteint les limites de la vitesse de déplacement des données
- Les applications modernes traitent des requêtes HTTP et consomment déjà 10 ms avec plusieurs requêtes de base de données et la logique métier ou le rendu avant même d’aller plus loin
- Il existe un chiffre magique pour la latence applicative : en dessous de 100 ms, la réponse paraît quasiment instantanée
- Une application réactive rend les utilisateurs heureux
- 100 ms semblent beaucoup, mais on les consomme très facilement sans s’en rendre compte
- Ce seuil des 100 ms est tellement important que les gens pré-rendent les pages et les placent sur un CDN pour réduire la latence
- Il vaut mieux rapprocher les données de l’application. À quel point ? Très près
- SQLite n’est pas seulement sur la même machine que votre application : il est inclus dans le processus même de l’application
- En mettant les données à côté de l’application, la latence par requête peut tomber à 10~20 microsecondes (μ)
- Soit 50 à 100x plus rapide qu’une requête Postgres dans la même région
- Mais ce n’est pas tout. On a pratiquement éliminé la latence par requête. Notre application est à la fois plus rapide et plus simple
- On peut découper les grosses requêtes en requêtes plus petites et plus faciles à gérer, et passer davantage de temps à exploiter le motif de requêtes N+1 pour construire de nouvelles fonctionnalités
- Minimiser la latence ne concerne pas seulement la production. Tester contre une base client/serveur classique a tendance à gonfler rapidement jusqu’à prendre plusieurs minutes en local, et la douleur continue une fois poussé en CI
- Réduire la boucle de feedback entre une modification de code et la fin des tests fait gagner du temps et aide à rester concentré pendant le développement
- Dans SQLite, une modification d’une ligne peut s’exécuter en mémoire et permettre de lancer des tests d’intégration en quelques secondes
Petit, rapide, fiable, distribué globalement : choisissez-en 4
- Litestream est distribué, répliqué et surtout facile à comprendre
- Sérieusement, « essayez-le ». Il y a peu de choses à savoir
- Voici mon argument :
- Si l’on construit une réplication fiable et simple d’usage pour SQLite, alors les applications full stack fonctionnant uniquement avec SQLite deviennent très attractives
- À l’époque des tutoriels « créer un blog avec Rails », cette option a été négligée, mais le SQLite d’aujourd’hui peut encaisser la plupart des charges d’écriture applicatives, et l’équilibrage de charge via des réplicas permet à de nombreuses instances de lire
- Litestream a aussi des limites
- Comme il a été conçu pour des applications mono-nœud, il ne fonctionne pas très bien sur les plateformes serverless ni avec les déploiements rolling
- Comme toutes les modifications doivent être restaurées de façon séquentielle, la restauration de la base peut prendre quelques minutes
- Nous préparons une fonctionnalité de réplication en temps réel, mais le modèle en processus séparé impose des limites dans le contrôle fin des garanties de réplication
- On peut faire mieux
- Mon travail de l’année écoulée a consisté à poser les fondations de Litestream et à me concentrer sur la justesse
- Je suis satisfait de l’endroit où nous sommes arrivés aujourd’hui
- Cela a commencé comme un simple outil de sauvegarde en streaming, mais évolue progressivement vers une base de données stable et distribuée
- Mon travail chez Fly.io consiste à rendre tout cela plus rapide et plus fluide
- Indépendamment de Fly.io, Litestream continuera de recevoir de nombreuses améliorations
- Litestream a trouvé un nouveau foyer chez Fly.io, mais restera un projet open source
- Mon plan pour les prochaines années est de le rendre plus utile, quel que soit l’endroit où s’exécutent les applications, et de voir jusqu’où le modèle SQLite peut aller
6 commentaires
Ça m’a donné envie de le relire attentivement une fois de plus.
J’ai déjà eu une idée similaire, mais là c’est beaucoup plus abouti et sérieux. J’ai été impressionné en le lisant. Ça me donne aussi envie d’essayer Litestream.
Ce serait encore mieux si on pouvait exécuter les requêtes à distance... 😢
Cela me fait penser au moment où Elixir est apparu. C’est un outil qui fournit au niveau du langage une base de données distribuée embarquée et l’orchestration, mais je ne sais pas vraiment si c’est l’avenir.
J’ai pris plaisir à le lire !
Je comptais le lire rapidement et en faire un résumé, mais en m’y mettant, c’était tellement intéressant que c’est devenu assez long.
Litestream - outil de réplication en streaming pour SQLite
Ça vaut sans doute le coup de le lire en lien avec la question Quelqu’un a-t-il déjà utilisé SQLite comme base de données primaire ?.
Il y a probablement aussi un lien avec Cloudflare présente D1, une base de données SQL pour Workers, dévoilé il y a quelques jours.
Consultez aussi les commentaires sur HN : https://news.ycombinator.com/item?id=31318708