MariaDB vs SQLite pour petits projets sur VPS : quand MariaDB est excessif

Cet article vous a aidé ?

Vous avez loué un petit VPS parce que vous êtes responsable. Puis vous avez installé MariaDB parce que vous êtes ambitieux. Maintenant votre « application simple » a un démon de base de données, un buffer pool, un système d’authentification, des tempêtes de connexions et une stratégie de sauvegarde que vous n’avez pas testée. Pendant ce temps, votre charge de travail est : « quelques utilisateurs, un cron, et un seul processus web qui lit principalement ».

C’est le moment d’admettre une vérité ennuyeuse : pour une grande classe de petits projets sur VPS, MariaDB n’est pas un choix de base de données. C’est un choix opérationnel. SQLite est souvent le meilleur choix par défaut — jusqu’à ce qu’il ne le soit plus.

La décision que vous prenez réellement

Les gens encadrent cela comme « SQLite vs MariaDB ». C’est un mensonge par omission. La vraie décision est :

  • Base de données embarquée sous forme de fichier (SQLite) : moins d’éléments en mouvement, moins de threads en arrière-plan, moins de réglages, moins de modes de défaillance. Vous échangez certains schémas de concurrence et certains outils opérationnels.
  • Service de base de données client-serveur (MariaDB) : protocole réseau, authentification, pool de connexions, maintenance en arrière-plan, options de réplication, et beaucoup de choses que vous pouvez mal régler à 2 h du matin.

Sur un petit VPS (1–2 vCPU, 1–4 Go RAM, SSD modeste), le facteur limitant n’est que rarement « l’ensemble des fonctionnalités SQL ». C’est typiquement l’un de :

  • pression mémoire et swap (l’assassin silencieux des performances).
  • pics de latence I/O (voisins bruyants, crédits de rafale, stockage bon marché).
  • trop de connexions ou de threads pour le CPU.
  • sauvegardes qui n’existent que dans votre imagination.
  • un schéma de concurrence qui semble acceptable en dev et qui s’écroule sous un peu de contention réelle.

Si votre appli est mono‑nœud, à faible ou moyenne cadence d’écritures, et que vous préférez livrer le produit plutôt que de babysitter un démon, SQLite mérite d’être considéré en premier. Si vous avez besoin de nombreux écrivains concurrents, d’un accès distant depuis plusieurs machines, ou de changements de schéma en ligne sans interruption, MariaDB commence à ressembler moins à un excès et plus à une supervision adulte.

Idée paraphrasée de Werner Vogels (mentalité ingénierie/fiabilité) : « Tout échoue, donc concevez en prévoyant l’échec. » Construisez votre couche de données autour de cette idée, pas autour des impressions.

Blague #1 : Exécuter MariaDB pour une petite application de loisir, c’est comme embaucher un comptable à plein temps pour gérer votre petite monnaie — impressionnant, mais la paperasse gagnera.

Faits et historique importants en production

Un peu de contexte n’est pas de la trivia ; il explique pourquoi ces systèmes se comportent comme ils le font.

  1. SQLite est embarqué par conception. C’est une bibliothèque liée à votre processus, pas un démon. C’est pourquoi le coût de « connexion » est microscopique et pourquoi les permissions de fichier deviennent soudain très importantes.
  2. SQLite est largement utilisé en production depuis 2000. Ce n’est pas une « technologie jouet ». Il est utilisé dans les navigateurs, les téléphones et d’innombrables systèmes embarqués parce qu’il est stable et ennuyeux.
  3. Le mode WAL de SQLite a été un tournant. Le Write-Ahead Logging a amélioré la concurrence pour de nombreuses charges lisant majoritairement en permettant des lecteurs pendant les écritures (avec des contraintes).
  4. MySQL est arrivé en premier ; MariaDB est un fork. MariaDB s’est séparé de MySQL après l’acquisition d’Oracle de Sun (et avec MySQL). Cette histoire de fork compte quand vous lisez de vieux conseils « MySQL » en supposant qu’ils s’appliquent.
  5. InnoDB est devenu le moteur de stockage par défaut. Les sémantiques transactionnelles, la récupération après crash et le verrouillage au niveau des lignes expliquent pourquoi il domine. C’est aussi pourquoi la taille mémoire et le comportement d’fsync comptent.
  6. Le modèle de verrouillage de SQLite est centré sur le fichier. Ce fichier unique est à la fois la magie et la contrainte. C’est simple, jusqu’à ce que votre charge ait de nombreux écrivains ou de longues transactions.
  7. MariaDB propose des pools de threads et plusieurs chemins d’exécution. Le réglage de la gestion des threads peut faire ou défaire les performances sur de petits CPU ; les paramètres par défaut peuvent être corrects ou catastrophiques selon le comportement des connexions.
  8. Les colonnes « typées » de SQLite sont plus flexibles qu’elles n’en ont l’air. L’affinité de type n’est pas la même chose qu’un typage strict, ce qui peut être une fonctionnalité ou un piège selon l’hygiène de vos données.
  9. MariaDB apporte des outils matures. Logs de requêtes lentes, alternatives au performance schema et options de réplication sont de vrais avantages quand vous avez besoin d’observabilité et de patterns de scale‑out.

Formes de charge : qui gagne où

Cas A : VPS unique, une instance d’appli, principalement des lectures

Choisissez SQLite sauf si vous avez une raison spécifique de ne pas le faire. Vous obtenez :

  • Pas de saut réseau.
  • Pas de pool de connexions requis (même si vous devez toujours utiliser l’accès applicatif intelligemment).
  • Un fichier unique que vous pouvez sauvegarder, checksummer et expédier.
  • Empreinte mémoire plus faible ; pas de buffer pool à dimensionner.

Avec le mode WAL et des transactions courtes, SQLite peut gérer un trafic surprenant. Le piège : les transactions longues et les habitudes « écrire pour chaque requête ».

Cas B : nombreux écrivains concurrents (file, API bavarde, écritures de type métriques)

MariaDB commence à gagner car il est conçu pour ordonnancer des charges d’écriture concurrentes avec des verrous au niveau ligne et des contrôles internes de concurrence. SQLite peut le faire, mais vous passerez plus de temps à lutter contre la contention des verrous qu’à profiter de la vie.

Cas C : plusieurs serveurs d’appli ou un job runner séparé

Si plusieurs machines doivent écrire dans la même base, SQLite est généralement le mauvais outil. Oui, vous pouvez mettre SQLite sur un stockage réseau. Non, vous ne devriez généralement pas le faire. Le moment où vous introduisez des systèmes de fichiers réseau dans une architecture « petit VPS », vous avez construit un simulateur de pannes.

Cas D : vous avez besoin de migrations en ligne et de réglages opérationnels

MariaDB vous donne plus de leviers : DDL en ligne dans de nombreux cas, meilleure introspection à l’exécution et patterns établis de migration/réplication. SQLite peut faire des migrations, mais vous n’aurez pas la même flexibilité opérationnelle lorsque vous êtes dans le cambouis.

Cas E : les données sont petites et précieuses

Le fichier unique de SQLite est séduisant pour des données « petites et précieuses » : état de configuration, jetons de facturation, feature flags, journaux d’audit pour une petite appli, caches importants. Votre histoire de sauvegarde et restauration peut être extrêmement simple — si vous la faites correctement.

Quand MariaDB est excessif (et pourquoi ça fait mal)

MariaDB n’est pas « lourd » dans le sens où les gens d’entreprise l’entendent. Il est lourd dans le sens où les petits serveurs le ressentent : un service en arrière-plan avec un appétit mémoire et beaucoup de threads concurrents qui ne se réduisent pas poliment.

La taxe cachée : mémoire et swap

Sur les petits VPS, l’échec MariaDB le plus courant n’est pas « mauvais index ». C’est la thrashing de swap. Quand MariaDB + appli + cache de pages de l’OS dépassent la RAM, le système va se dégrader en un effondrement au ralenti. La latence devient non linéaire. Les requêtes font la queue. Les timeouts déclenchent des retries. La charge augmente. Vous assistez au brasier.

SQLite n’évite pas magiquement les problèmes mémoire, mais son empreinte de base est plus petite et il n’exécute pas un démon qui veut être utile en mettant en cache tout l’univers.

Connexions, threads et le sophisme « c’est juste un VPS »

Les petites applis utilisent souvent une taille de pool ORM par défaut de 10–50 par process parce que c’est ce qu’a dit le billet de blog. Sur un petit VPS, cela peut signifier :

  • Trop de threads DB
  • Surcharge de commutation de contexte
  • Contention de verrous amplifiée par la concurrence
  • Surcharge mémoire par connexion

SQLite évite en grande partie les « tempêtes de connexions » parce que les connexions sont intra‑processus et bon marché. Vous pouvez quand même vous tirer une balle dans le pied avec la concurrence, mais il est plus difficile de lancer accidentellement 400 connexions TCP vers soi-même.

Surface opérationnelle

MariaDB apporte privilèges, exposition réseau, TLS, gestion des utilisateurs, propriété du répertoire de données, rotation des logs, mises à niveau avec compatibilité et tâches en arrière-plan. Rien de tout cela n’est mal en soi. Mais pour un petit projet, chacun est un puits de temps potentiel.

Le test olfactif de l’excès

MariaDB est probablement excessif si la plupart de ces affirmations sont vraies :

  • VPS unique, instance d’appli unique.
  • Les écritures sont occasionnelles (secondes à minutes entre chaque écriture, ou petits lots).
  • Le jeu de données tient confortablement dans le cache de pages OS (ou est juste petit).
  • Vous n’avez pas besoin d’accès distant depuis plusieurs hôtes.
  • Vous n’avez pas besoin d’une forte concurrence d’écritures.
  • Vous préférez des sauvegardes et restaurations ultra simples.

SQLite : les pièges à connaître

La concurrence concerne les transactions, pas le vœu pieux

SQLite peut gérer de nombreux lecteurs et un seul écrivain à la fois. Le mode WAL améliore la coexistence lecture/écriture, mais il ne rend pas « nombreux écrivains » gratuits. Le pire schéma est une transaction d’écriture longue ou toute transaction qui maintient des verrous pendant que vous effectuez des I/O réseau ou un travail applicatif complexe.

Règle de conception : gardez les transactions courtes, faites le travail hors transaction, puis écrivez.

Le mode WAL n’est pas optionnel pour la plupart des charges web

Si vous construisez une appli web et que vous restez en mode journal de rollback par défaut, vous choisissez volontairement plus de douleur de verrouillage. WAL est généralement le bon choix. Il change aussi la sémantique de sauvegarde : vous devez tenir compte des fichiers WAL.

Les paramètres de durabilité sont de vrais compromis

SQLite facilite la définition de pragmas comme synchronous=NORMAL et de se croire sorcier des performances. Vous échangez aussi certaines garanties de durabilité. Si votre VPS peut perdre l’alimentation ou si votre hyperviseur peut redémarrer brutalement (ça peut arriver), vous devez savoir à quoi vous vous engagez.

Les systèmes de fichiers réseau sont un piège courant

SQLite attend des sémantiques POSIX raisonnables. Sur beaucoup de systèmes de fichiers réseau, le verrouillage et le comportement d’fsync sont… une danse interprétative. SSD local sur le VPS : bien. NFS/SMB/« une chose partagée » : généralement non.

Un fichier signifie un seul jeu de permissions

La base est un fichier. C’est merveilleusement simple et aussi brutalement littéral. Si votre déploiement change d’utilisateur, de conteneur ou de répertoire de travail, vous pouvez casser votre appli avec un chmod.

MariaDB : les pièges que vous rencontrerez

Les configs par défaut ne sont pas « sûres pour les petits »

Les valeurs par défaut de MariaDB sont souvent sensées pour des serveurs à usage général, mais « usage général » suppose plus de ressources que votre VPS à 5 $. Le buffer pool, les buffers par connexion et les threads en arrière-plan peuvent dépasser ce que vous pouvez vous permettre.

La mémoire par connexion est la fuite RAM silencieuse

Ce n’est pas une fuite, c’est pire : c’est « fonctionnement selon la conception ». Chaque connexion peut allouer des buffers pour tri, jointure, tables temporaires, etc. Résultat : les tempêtes de connexions se transforment en tempêtes de mémoire. Vous voyez le swap, puis les timeouts, puis la panique.

fsync et durabilité : les performances dépendent du stockage

La durabilité d’InnoDB dépend du flush des logs. Sur un stockage VPS bon marché, la latence d’fsync peut grimper. Vous verrez des arrêts périodiques et votre appli blâmera la « lenteur de la base » comme si c’était un défaut de personnalité.

Les sauvegardes sont un processus, pas un fichier

Avec SQLite, la sauvegarde peut être une opération au niveau fichier (faite correctement). Avec MariaDB, des sauvegardes cohérentes nécessitent des outils et de la réflexion : dumps logiques, copies physiques, comportement de verrouillage, positionnement pour la réplication si vous prenez cette voie. Rien de tout cela n’est difficile, mais il est facile de ne pas le faire.

Empreinte sécurité

SQLite n’a pas de port d’écoute. MariaDB en a un. Si vous l’exposez sur Internet sans le vouloir, vous apprendrez à quel point le password spraying est populaire. « Mais j’ai utilisé un mot de passe fort » n’est pas une stratégie ; c’est un espoir.

Blague #2 : Ouvrir le port 3306 sur Internet est une excellente façon de rencontrer des bots qui ne dorment jamais — contrairement à votre rotation d’astreinte.

Tâches pratiques : commandes, sorties et décisions

Vous ne choisissez pas des bases de données en lisant des matrices de fonctionnalités. Vous les choisissez en demandant à la machine ce qu’elle fait. Ci‑dessous des tâches concrètes que j’exécute sur de petits VPS. Chacune inclut la commande, une sortie d’exemple, ce que cela signifie et la décision que vous prenez.

Task 1: Is the VPS swapping?

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           1.9Gi       1.6Gi       120Mi        32Mi       230Mi       170Mi
Swap:          1.0Gi       780Mi       244Mi

Ce que cela signifie : Le swap est fortement utilisé. Sur un petit VPS, cela se corrèle avec des stalls aléatoires de plusieurs secondes.

Décision : Si vous êtes sur MariaDB, réduisez l’empreinte mémoire (buffer pool, nombre de connexions) ou passez à SQLite si la charge convient. Si vous êtes sur SQLite, réduisez la mémoire applicative ou ajoutez de la RAM ; SQLite n’est pas la cause, mais il peut souffrir aussi.

Task 2: Are we in I/O wait hell?

cr0x@server:~$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  1 798720 122880  11264 215040    0    5   120   980  520  840 18  7 55 20  0
 1  2 798720 118432  11264 213120    0   12   210  1460  600  920 12  6 48 34  0

Ce que cela signifie : Un wa (I/O wait) élevé et du swapping (so) indiquent la latence de stockage et la pression mémoire.

Décision : Réparez le stockage et la RAM d’abord. Ne tunez pas le SQL pendant que l’hôte se noie.

Task 3: Is MariaDB the top memory hog?

cr0x@server:~$ ps -eo pid,comm,rss,pcpu --sort=-rss | head
 2481 mariadbd           612340  18.2
 3022 python3            248120   9.1
 1102 nginx               45200   0.3

Ce que cela signifie : Le RSS de MariaDB est ~600MB ; sur 2GB cela peut aller, sur 1GB ce n’est pas acceptable.

Décision : Si votre jeu de données est petit et que la concurrence d’écritures est faible, envisagez SQLite pour récupérer de la RAM. Sinon, ajustez InnoDB buffer pool et l’utilisation des connexions.

Task 4: How many connections are we actually using (MariaDB)?

cr0x@server:~$ sudo mariadb -e "SHOW GLOBAL STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections';"
Variable_name	Value
Threads_connected	87
Variable_name	Value
max_connections	151

Ce que cela signifie : Vous êtes proche du plafond. Chaque connexion a un coût.

Décision : Corrigez la taille du pool applicatif, ajoutez un pooler ou réduisez la concurrence. N’augmentez pas simplement max_connections sur un petit VPS à moins d’avoir budgété la RAM.

Task 5: Is the slow query log telling the truth (MariaDB)?

cr0x@server:~$ sudo mariadb -e "SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time';"
Variable_name	Value
slow_query_log	OFF
Variable_name	Value
long_query_time	10.000000

Ce que cela signifie : Le logging est désactivé et le seuil est trop élevé. Vous êtes aveugle.

Décision : Activez temporairement le slow query log avec un seuil bas (0.2–0.5s) pour attraper les vrais coupables. Puis réglez-le à un niveau moins verbeux pour éviter le spam de logs.

Task 6: Are we CPU-bound or I/O-bound (quick look)?

cr0x@server:~$ top -b -n 1 | head -15
top - 12:00:11 up 21 days,  2:14,  1 user,  load average: 3.12, 2.44, 1.98
Tasks: 132 total,   2 running, 130 sleeping,   0 stopped,   0 zombie
%Cpu(s): 72.0 us,  8.0 sy,  0.0 ni, 12.0 id,  8.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   2048.0 total,    140.0 free,   1550.0 used,    358.0 buff/cache

Ce que cela signifie : Un CPU utilisateur élevé suggère l’exécution de requêtes ou la logique applicative ; un I/O wait non négligeable suggère aussi de la latence de stockage.

Décision : Si le CPU est élevé avec peu de requêtes, vérifiez les plans de requête et les index. Si les pics de I/O wait coïncident avec des commits, vérifiez le comportement d’fsync et la santé du disque.

Task 7: SQLite quick health check (integrity)

cr0x@server:~$ sqlite3 /var/lib/myapp/app.db "PRAGMA integrity_check;"
ok

Ce que cela signifie : Le fichier de base est structurellement cohérent.

Décision : Si ce n’est pas « ok », arrêtez les écritures, faites une copie et planifiez la récupération. La corruption est rare mais pas imaginaire — surtout avec un stockage non sûr ou des arrêts brutaux.

Task 8: SQLite journal mode and synchronous settings

cr0x@server:~$ sqlite3 /var/lib/myapp/app.db "PRAGMA journal_mode; PRAGMA synchronous;"
wal
2

Ce que cela signifie : Le mode WAL est activé ; synchronous=2 signifie FULL (durable, plus lent).

Décision : Pour de nombreuses applis VPS, WAL est indispensable. Conservez synchronous FULL si la correction des données compte. Si vous choisissez NORMAL, faites-le en connaissance de cause et documentez le risque.

Task 9: SQLite lock contention symptoms (busy timeouts)

cr0x@server:~$ sqlite3 /var/lib/myapp/app.db "PRAGMA busy_timeout;"
0

Ce que cela signifie : Aucun busy timeout ; les écrivains peuvent échouer immédiatement en cas de contention.

Décision : Définissez un busy timeout raisonnable dans l’appli (ou via PRAGMA par connexion) et réduisez la durée des transactions. Les busy timeouts sont des pansements ; les transactions longues sont l’infection.

Task 10: MariaDB InnoDB buffer pool size check

cr0x@server:~$ sudo mariadb -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
Variable_name	Value
innodb_buffer_pool_size	1073741824

Ce que cela signifie : Buffer pool de 1GB. Sur un système 1–2GB cela peut être trop une fois que vous incluez l’OS, le cache de pages et la mémoire applicative.

Décision : Sur les petits VPS, commencez conservateur. Si du swapping survient, réduisez-le. La RAM que vous n’avez pas n’est pas un cache, c’est un générateur de timeouts.

Task 11: MariaDB: are we hitting temporary tables on disk?

cr0x@server:~$ sudo mariadb -e "SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables'; SHOW GLOBAL STATUS LIKE 'Created_tmp_tables';"
Variable_name	Value
Created_tmp_disk_tables	1842
Variable_name	Value
Created_tmp_tables	9621

Ce que cela signifie : Une fraction significative des tables temporaires va sur disque, ce qui peut être lent sur un stockage bon marché.

Décision : Vérifiez les requêtes qui provoquent des tris/joints ; ajoutez des index ; envisagez d’augmenter les limites des tmp tables seulement si vous avez de la RAM disponible (rare sur les petits VPS).

Task 12: MariaDB: quick slowest queries snapshot (processlist)

cr0x@server:~$ sudo mariadb -e "SHOW FULL PROCESSLIST;"
Id	User	Host	db	Command	Time	State	Info
412	app	user@localhost	mydb	Query	12	Sending data	SELECT * FROM events WHERE user_id=...
431	app	user@localhost	mydb	Sleep	55		NULL

Ce que cela signifie : Une requête tourne depuis 12 secondes ; de nombreuses connexions en sommeil peuvent indiquer des problèmes de pool.

Décision : Trouvez cette requête, expliquez‑la, ajoutez un index ou réécrivez. Pour les sleepers, réduisez la taille du pool ou la durée de vie ; arrêtez d’accumuler des connexions inactives sur une petite machine.

Task 13: MariaDB: verify you’re not exposed on the network

cr0x@server:~$ sudo ss -lntp | grep -E '3306|mysqld|mariadbd'
LISTEN 0      80           127.0.0.1:3306       0.0.0.0:*    users:(("mariadbd",pid=2481,fd=21))

Ce que cela signifie : Lié à localhost uniquement, ce qui est bon pour les applis mono‑hôtes.

Décision : Si l’écoute est sur 0.0.0.0, corrigez bind-address et les règles de firewall immédiatement. Ne « planifiez pas pour plus tard ». Plus tard, c’est quand le credential stuffing commence.

Task 14: SQLite backup the right way (online-safe)

cr0x@server:~$ sqlite3 /var/lib/myapp/app.db ".backup '/var/backups/app.db.bak'"

Ce que cela signifie : SQLite crée une sauvegarde cohérente même lorsque la BD est utilisée (dans les garanties de SQLite).

Décision : Utilisez .backup ou l’API de backup, pas un simple cp, à moins d’avoir arrêté les écrivains et pris en compte les fichiers WAL.

Task 15: MariaDB logical backup sanity check

cr0x@server:~$ sudo mysqldump --single-transaction --quick --routines mydb | head
-- MySQL dump 10.19  Distrib 10.11.6-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost    Database: mydb
-- ------------------------------------------------------
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;

Ce que cela signifie : Vous pouvez produire un dump logique cohérent sans verrouiller agressivement les tables (pour InnoDB).

Décision : Si ce dump prend trop de temps ou impacte les performances, vous devrez peut‑être mieux planifier ou vous êtes en train de dépasser le plan VPS.

Task 16: Disk space: are you about to fail in a dumb way?

cr0x@server:~$ df -h /var/lib
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        25G   24G  0.9G  97% /

Ce que cela signifie : Vous êtes à un pic de log d’une panne. Les bases de données détestent « disque plein ». Elles vous puniront de façon créative.

Décision : Nettoyez les logs, déplacez les sauvegardes hors‑hôte, agrandissez le disque. Ce n’est pas une maintenance optionnelle ; c’est la disponibilité.

Racourci de diagnostic rapide

Ceci est la séquence « cessez de deviner ». Exécutez‑la quand votre appli sur petit VPS est lente et que les gens commencent à blâmer « la base de données » comme un collègue qui ne répond jamais.

Premier : contraintes au niveau hôte (60 secondes)

  1. Swap et RAM : free -h. Si le swap est actif et la RAM faible, c’est votre suspect principal.
  2. I/O wait : vmstat 1 5 ou iostat -xz 1 5 (si installé). Un wa élevé signifie que le stockage fait partie de l’histoire.
  3. Espace disque : df -h. Les disques presque pleins causent des stalls, des bizarreries et parfois une corruption après crash.

Second : réalité au niveau processus (2–3 minutes)

  1. Qui utilise CPU et mémoire : ps trié par RSS et top. Si MariaDB domine la RAM sur un hôte 1GB, ajustez ou repensez l’architecture.
  2. Nombre de connexions (MariaDB) : vérifiez Threads_connected par rapport à votre configuration de pool.
  3. Descripteurs de fichiers ouverts (les deux) : si votre appli atteint des limites, SQLite peut ne pas ouvrir la BD ; MariaDB peut ne pas accepter de connexions.

Troisième : goulots spécifiques base de données (5–15 minutes)

  1. MariaDB : vérifiez processlist pour les longues requêtes ; activez brièvement le slow query log ; cherchez les tmp disk tables et les stalls d’InnoDB log.
  2. SQLite : vérifiez le mode WAL ; contrôlez busy_timeout et les logs applicatifs pour « database is locked » ; identifiez les longues transactions ; lancez integrity_check si vous suspectez une corruption.
  3. Couche appli : confirmez que votre ORM n’exécute pas des N+1, et que vous ne démarrez pas une transaction par requête sans raison.

Si vous ne faites qu’une chose : corrigez le swap et l’I/O wait avant de toucher au tuning SQL. La plupart des problèmes de « performance base de données » sur petits VPS sont en réalité des problèmes d’étouffement de l’hôte déguisés en SQL.

Trois mini-histoires d’entreprise (de l’archive cicatrisée)

1) Incident causé par une mauvaise hypothèse : « SQLite ne fait pas de concurrence »

Un petit outil interne vivait sur une VM unique. Il traitait un flux modeste d’événements, écrivait quelques lignes par seconde et servait des tableaux de bord à une douzaine de personnes. Il a démarré sur SQLite, a bien tourné, et personne n’y a pensé pendant des mois — jusqu’à ce qu’un ingénieur lise un fil affirmant « SQLite n’est pas pour la production ».

Ils l’ont remplacé à la hâte par MariaDB, parce que production = client-serveur, non ? Ils ont mis en place une instance MariaDB par défaut, migré le schéma et pointé l’appli dessus. Ça a marché en staging. Ça a marché sur leur laptop. Ça a marché pendant un jour.

Puis la VM a commencé à ramer. Les tableaux de bord ont expiré. La file de jobs a grossi. L’équipe a chassé des « requêtes lentes », ajouté quelques index et obtenu une amélioration brève. Mais le véritable coupable était simple : l’instance MariaDB et l’appli se disputaient 2GB de RAM, et sous charge l’hôte swapait. Les pics de latence ont provoqué des retries. Les retries ont provoqué plus de connexions. Plus de connexions ont provoqué plus de mémoire. Ça a spiré.

La mauvaise hypothèse n’était pas sur les fonctionnalités SQL. C’était sur le comportement système. SQLite allait bien parce qu’il avait une empreinte plus petite et ne déclenchait pas le swap. MariaDB aurait aussi pu aller, mais pas avec le pool de connexions par défaut et sans budget mémoire.

La correction n’a rien d’héroïque : ils sont revenus à SQLite, ont activé WAL, ajouté un busy timeout et modifié l’appli pour grouper les écritures. L’incident s’est terminé non par une percée de montée en charge, mais par un rappel que « prêt pour la production » signifie « approprié opérationnellement », pas « le plus populaire sur les offres d’emploi ».

2) Optimisation qui a mal tourné : « Rendre SQLite plus rapide »

Une API sur un VPS économique utilisait SQLite. Les écritures étaient petites mais fréquentes. Quelqu’un a remarqué une latence d’écriture occasionnelle et a décidé d’« optimiser » en changeant des pragmas : synchronous=OFF, caches plus grands, stockage temporaire agressif en mémoire. Les benchmarks sur la machine dev semblaient fantastiques. Ils ont déployé un vendredi, parce que l’optimisme est une source d’énergie.

Pendant quelques jours, c’était plus rapide. Puis le VPS a subi un reboot imprévu — maintenance hyperviseur, le type sans invitation au calendrier. L’appli est revenue et a commencé à échouer des requêtes. Le fichier SQLite n’était pas catastrophiquement corrompu, mais l’état applicatif était incohérent. Quelques lignes critiques manquaient dans une table censée être append‑only.

Le débogage a été vilain parce que la base était « bien » structurellement. Pas de corruption évidente. Juste des écritures manquantes qui n’avaient jamais été rendues durables. C’est le prix de synchronous=OFF : vous avez demandé à SQLite de vous mentir sur la durabilité, et il l’a fait.

Ils ont restauré depuis des sauvegardes et retraité certains événements. Puis ils ont remis les pragmas à des valeurs sensées, gardé WAL, et au lieu d’optimiser les pragmas, ont optimisé le comportement applicatif réel : moins de commits, plus de batching, transactions plus courtes et index correctement définis. Les performances sont restées bonnes. Les données ont cessé de disparaître.

3) Pratique ennuyeuse mais correcte qui a sauvé la journée : « Tester la restauration »

Un petit SaaS tournait sur un VPS unique avec MariaDB. Rien de sophistiqué : un primaire, pas de réplica, pas d’outillage élaboré. Mais l’opérateur avait un rituel : tests de restauration hebdomadaires sur une VM jetable. Pas un plan théorique, une restauration effective.

Un matin, le disque du VPS a commencé à renvoyer des erreurs I/O. Le service DB a commencé à planter. Le système de fichiers s’est remonté en lecture seule. Les tickets de support sont arrivés, puis se sont arrêtés, parce que l’appli était down. L’opérateur n’a pas tenté des réparations héroïques. Il a arrêté le service, capturé les logs possibles et monté un nouveau VPS.

Parce que les tests de restauration étaient routiniers, les étapes de récupération étaient écrites et correctes. Ils ont restauré le dump de la nuit précédente, rejoué un petit lot d’événements applicatifs depuis une file, et remis le service en ligne. Le downtime a été pénible, mais limité. Pas d’improvisation sous stress.

La pratique ennuyeuse n’était pas « utilisez MariaDB ». C’était « testez les restaurations ». Les bases ne tombent pas selon votre calendrier, donc votre plan de reprise ne peut pas être une hypothèse non testée.

Erreurs fréquentes : symptômes → cause racine → correction

1) Erreurs « Database is locked » sous SQLite avec peu de trafic

Symptômes : 500s sporadiques, logs montrant database is locked, pics lors de jobs en arrière‑plan.

Cause racine : transactions longues (souvent « BEGIN; faire du travail; appeler un service externe; COMMIT »), pas de busy timeout, mode journal rollback, ou trop d’écrivains.

Correction : activez WAL ; raccourcissez les transactions ; définissez busy timeout ; groupez les écritures ; assurez‑vous qu’il n’y a qu’un seul chemin d’écriture si nécessaire.

2) MariaDB « Too many connections » sur un petit VPS

Symptômes : erreurs applicatives de connexion ; logs DB montrant des limites de connexion ; CPU qui monte pendant les incidents.

Cause racine : pools ORM surdimensionnés, réutilisation des connexions manquante, ou retries provoquant des tempêtes.

Correction : réduisez la taille du pool ; implémentez un pooling correct ; limitez les retries avec backoff ; surveillez Threads_connected.

3) Stalls périodiques de 2–10 secondes sur des écritures MariaDB

Symptômes : pics de latence autour des commits ; le CPU n’est pas saturé ; utilisateurs se plaignent de « lenteur aléatoire ».

Cause racine : pics de latence d’fsync du stockage, disque VPS bon marché, flush des logs InnoDB.

Correction : passez à un stockage meilleur ; réduisez l’amplification d’écriture (batching) ; assurez‑vous que la configuration des journaux InnoDB est sensée ; évitez de saturer le disque avec des jobs non liés en même temps.

4) SQLite « marche en dev » mais échoue en déploiement conteneurisé

Symptômes : impossible d’ouvrir le fichier DB, permission denied, ou fichier DB réinitialisé de façon inattendue.

Cause racine : mauvais montage de volume, UID/GID incorrect, ou système de fichiers éphémère dans le conteneur.

Correction : volume persistant explicite ; propriété correcte ; définir le chemin de fichier via config ; assurez‑vous que les déploiements atomiques ne remplacent pas le fichier DB.

5) MariaDB consomme toute la RAM lentement au fil du temps

Symptômes : usage mémoire qui croît ; swap apparaît ; performances dégradées après quelques jours.

Cause racine : buffer pool trop grand, buffers par connexion déclenchés par des requêtes complexes, trop de connexions concurrentes.

Correction : réduisez le buffer pool ; baissez la concurrence ; réécrivez les requêtes coûteuses ; surveillez les tables temporaires et l’activité de tri.

6) « La sauvegarde existe » mais la restauration échoue

Symptômes : vous exécutez un exercice de restauration et ça échoue, ou les données restaurées sont incohérentes.

Cause racine : sauvegarde SQLite prise incorrectement alors que WAL est actif ; dump MariaDB pris sans consistance transactionnelle ; routines manquantes ; mauvaises hypothèses sur charset/collation.

Correction : SQLite : utilisez .backup ou arrêtez les écrivains et copiez DB+WAL ; MariaDB : utilisez --single-transaction pour InnoDB et testez la restauration régulièrement.

7) « SQLite est lent » pendant de grands rapports

Symptômes : SELECT longs bloquant les écritures ; requêtes web expirent.

Cause racine : lectures longues maintenant des snapshots ; indexes insuffisants ; scans larges sur des disques bon marché.

Correction : ajoutez des index ; paginez ; déplacez le reporting vers un réplica/fichier ETL ; envisagez MariaDB si reporting et écritures doivent coexister avec une forte concurrence.

8) Mise à niveau MariaDB qui casse l’appli

Symptômes : requêtes qui se comportent différemment ; changements de stricte ; incompatibilité de plugin d’authentification.

Cause racine : valeurs par défaut spécifiques à une version et différences de compatibilité entre variantes MySQL/MariaDB ; tests en staging insuffisants.

Correction : figez les versions ; testez les mises à jour en staging avec des données réelles ; enregistrez les diffs de config ; ayez un plan de rollback.

Listes de contrôle / plan étape par étape

Étape par étape : choisir SQLite sur un petit VPS (la voie « livrer »)

  1. Confirmez la forme de la charge : un nœud, écritures faibles à modérées, pas besoin d’écrivains multi‑hôtes.
  2. Activez le mode WAL : définissez PRAGMA journal_mode=WAL; lors de l’initialisation de la BD.
  3. Définissez une durabilité sensée : préférez synchronous=FULL pour la correction ; considérez NORMAL seulement si vous acceptez une perte de données en cas de coupure brutale.
  4. Définissez busy timeout : évitez les échecs immédiats sous contention ; corrigez tout de même la longueur des transactions.
  5. Concevez pour un seul écrivain : sérialisez les chemins d’écriture intensifs ou regroupez les écritures via une file en‑processus.
  6. Sauvegardes : utilisez .backup ; envoyez les sauvegardes hors‑hôte ; testez la restauration mensuellement.
  7. Observabilité : loggez la latence des requêtes dans l’appli ; capturez le contexte des erreurs « database is locked ».

Étape par étape : si vous insistez pour MariaDB sur un petit VPS (faites‑le en sécurité)

  1. Liez à localhost : exposez la base seulement si vous avez absolument besoin d’un accès distant.
  2. Budgetez la RAM : dimensionnez le buffer pool de façon conservatrice ; laissez de la RAM pour l’OS et l’appli.
  3. Corrigez le pooling de connexions : petites tailles de pool ; plafonnez la concurrence ; évitez connect/disconnect par requête.
  4. Activez l’observabilité minimale : slow query log avec un seuil sensé lors du dépannage ; surveillez les tmp disk tables.
  5. Sauvegarde et drills de restauration : automatisez les dumps ; faites de la rotation ; testez les restaurations sur une instance propre.
  6. Planifiez les upgrades : figez la version ; testez ; planifiez ; ayez un rollback.

Étape par étape : chemin de migration (SQLite maintenant, MariaDB plus tard) sans drame

  1. Gardez le SQL portable : évitez les bizarreries SQLite si vous comptez migrer (p.ex. dépendre de la typage flexible comme « fonctionnalité »).
  2. Utilisez des migrations explicites : versionnez votre schéma, ne comptez pas sur « créer les tables au démarrage ».
  3. Abstraire l’accès BD : gardez une petite couche d’accès aux données ; ne dispersez pas du SQL brut partout sauf si vous aimez l’archéologie.
  4. Plan d’export/import : utilisez un format de dump répétable (CSV pour les tables, ou export applicatif) et vérifiez les comptes de lignes et checksums.
  5. Double‑exécution brièvement : écrivez dans l’un, lisez depuis l’autre uniquement pendant une fenêtre de cutover planifiée, si l’appli le supporte.
  6. Coupez avec gel : arrêtez les écritures, faites la synchronisation finale, basculez, validez, puis reprenez.

FAQ

1) SQLite est‑il « prêt pour la production » pour une appli web sur VPS ?

Oui, si votre charge correspond : nœud unique, concurrence d’écritures modeste, transactions courtes, mode WAL et vraies sauvegardes. « Prêt pour la production » concerne le comportement en cas de panne, pas la présence d’un démon.

2) Combien d’utilisateurs concurrents SQLite peut‑il gérer ?

Mauvaise unité. Pensez en termes d’écrivains concurrents et de durée des transactions. Beaucoup de lecteurs passent bien ; beaucoup d’écrivains avec des transactions longues feront mal. Si votre appli écrit à chaque requête, vous construisez une charge d’écriture même si ce n’était pas l’intention.

3) Le mode WAL résout‑il le verrouillage SQLite ?

Il améliore le cas courant en permettant des lecteurs pendant les écritures, mais il ne rend pas les écritures concurrentes. Vous avez toujours un écrivain à la fois. Il faut toujours garder les transactions courtes et éviter les verrous longue durée.

4) Puis‑je mettre SQLite sur NFS pour le partager entre serveurs ?

Vous pouvez, mais vous misez vos données sur les sémantiques du système de fichiers et la stabilité réseau. Pour la plupart des petites équipes, c’est un mauvais pari. Si vous avez besoin d’écrivains multi‑hôtes, vous êtes en territoire MariaDB (ou une autre BD client‑serveur).

5) Pourquoi MariaDB paraît-il plus lent sur un petit VPS que SQLite ?

Il n’est pas toujours plus lent, mais il peut l’être : surcharge mémoire, plus de threads, pression d’fsync et protocole réseau même en localhost. Sur des hôtes contraints, la surcharge devient une latence visible par l’utilisateur.

6) Quelle est la sauvegarde la plus simple et sûre pour SQLite ?

sqlite3 app.db ".backup 'app.db.bak'", puis copiez la sauvegarde hors‑hôte. Testez les restaurations. Si vous copiez juste le fichier live sans tenir compte des WAL, vous risquez des sauvegardes incohérentes.

7) Quelle est la sauvegarde la plus simple et sûre pour MariaDB sur un VPS unique ?

mysqldump --single-transaction pour les tables InnoDB, programmé hors‑pic, tourné en rotation, copié hors‑hôte et testé en restauration. Les backups physiques sont plus rapides mais ajoutent de la complexité opérationnelle.

8) Quand dois‑je passer de SQLite à MariaDB ?

Quand vous avez besoin d’accès multi‑hôtes, d’une forte concurrence d’écritures, d’outils opérationnels plus riches, ou que vous passez du temps à contourner la contrainte « un écrivain » de SQLite. Aussi quand vous devez évoluer au‑delà d’un nœud unique de façon fiable.

9) MariaDB est‑il plus sûr que SQLite ?

Pas automatiquement. Les deux peuvent être sûrs ou dangereux selon la configuration et la discipline opérationnelle. Les risques de SQLite concernent souvent le verrouillage et la justesse des sauvegardes ; ceux de MariaDB concernent plutôt le tuning des ressources, l’exposition et la complexité opérationnelle.

10) Puis‑je utiliser les deux ?

Oui, et parfois c’est l’approche la plus propre : SQLite pour l’état local et les files ; MariaDB pour les données transactionnelles partagées. Soyez simplement honnête sur la complexité que vous ajoutez.

Étapes suivantes que vous pouvez faire aujourd’hui

  • Si vous êtes indécis : mesurez votre concurrence d’écritures et la durée des transactions. C’est la variable pivot. Pas « les fonctionnalités ».
  • Si vous êtes sur MariaDB sur un petit VPS : vérifiez le swap, la taille du buffer pool et le nombre de connexions. Limitez les pools. Liez à localhost. Activez le slow query log brièvement lors du dépannage.
  • Si vous êtes sur SQLite : activez le mode WAL, définissez un busy timeout et auditez votre code pour les transactions longues. Implémentez la routine .backup et testez une restauration.
  • Si vous prévoyez de croître : gardez vos migrations de schéma disciplinées et votre SQL portable pour que la migration vers MariaDB plus tard soit un changement planifié, pas une réécriture nocturne.

La « bonne » base de données pour un petit projet sur VPS est celle qui reste discrète tout en restant honnête sur les pannes. SQLite est souvent cette base. MariaDB est excellent quand vous en avez réellement besoin. Ne payez pas la taxe opérationnelle trop tôt à moins d’être sûr d’utiliser les services que vous avez achetés.

← Précédent
MariaDB vs PostgreSQL : Stockage en conteneur — vérité sur les performances Bind Mount vs Volume
Suivant →
Déconnexions USB en passthrough sur Proxmox : alimentation, autosuspend et correctifs de stabilité

Laisser un commentaire