Sauvegardes MySQL vs SQLite : laquelle est la plus facile à restaurer sous pression

Cet article vous a aidé ?

Les sauvegardes ne tombent pas en panne pendant votre exercice trimestriel sur table. Elles tombent en panne à 02:17, quand le téléphone d’astreinte vibre sur la table de nuit et que votre cerveau négocie encore avec la réalité.

À ce moment-là, vous ne vous souciez pas d’une architecture élégante. Vous ne pensez qu’à une chose : à quelle vitesse puis-je restaurer, prouver que c’est correct, et débloquer les utilisateurs sans aggraver les dégâts ? MySQL et SQLite peuvent tous deux être récupérés. La question est : lequel est plus facile à restaurer quand vous êtes fatigué, pressé et avec des informations incomplètes.

Ce que « plus facile à restaurer » signifie vraiment

La plupart des comparaisons entre les sauvegardes MySQL et SQLite sont écrites par des gens qui n’ont restauré aucun des deux pendant que Slack était en train de fondre. Sous pression, « plus facile » n’est pas « moins de fonctionnalités ». C’est une checklist de choses que vous pouvez faire rapidement, de façon répétable et sûre.

Les questions de restauration qui comptent à 02:17

  • Ai-je une sauvegarde cohérente ? Pas « un fichier existe ». Cohérent signifie qu’elle représente un point dans le temps réel sans pages déchirées ni transactions à moitié écrites.
  • Puis-je restaurer sans deviner ? Idéalement : une commande et une procédure connue. En réalité : il faudra du jugement, mais moins d’impasses aide.
  • Puis-je valider rapidement ? Si la vérification prend des heures, on la sautera. Alors vous découvrirez que la sauvegarde est cassée au pire moment.
  • Puis-je faire une restauration point‑dans‑le‑temps (PITR) ? Si non, « nous avons restauré » peut aussi signifier « nous avons perdu les six dernières heures ».
  • Que se passe‑t‑il si la couche de stockage est le problème ? La corruption n’est pas polie. Elle ressemblera volontiers à un bug applicatif jusqu’à ce que vous soyez profondément en déni.

Voici la vérité opérationnelle : SQLite est simple parce que c’est principalement un fichier, et MySQL est récupérable parce que c’est un système avec des outils éprouvés en production. Sous pression, les deux peuvent être faciles, et les deux peuvent être des pièges. La différence tient au type de piège.

Une citation à garder dans votre runbook : L’espoir n’est pas une stratégie. — General Gordon R. Sullivan

C’est l’état d’esprit de la restauration. Ne comptez pas sur l’espoir que la copie de fichier est cohérente. Ne comptez pas sur l’espoir que les binlogs existent. Ne comptez pas sur l’espoir que le WAL a été inclus. Prouvez‑le.

Faits intéressants et contexte historique (les parties qui comptent)

Quelques détails historiques expliquent pourquoi chaque système se comporte comme il le fait pendant la sauvegarde et la restauration.

  1. SQLite a commencé en 2000 comme base de données embarquée pour des outils ayant besoin d’un moteur SQL sans processus serveur. Son histoire de sauvegarde consiste à « copier les données en toute sécurité », pas à « coordonner un cluster ».
  2. SQLite est célèbre pour être « sans serveur » : pas de démon, pas de protocole réseau. Cette simplicité est une superforce pour la restauration — jusqu’à ce que la concurrence et la sémantique du système de fichiers interviennent.
  3. Le mode WAL de SQLite est devenu courant dans les années 2010 car il améliore la concurrence. Il change aussi ce que signifie « une sauvegarde » : le fichier .db seul peut ne pas contenir les dernières données validées.
  4. L’InnoDB de MySQL est devenu le moteur par défaut dans MySQL 5.5. Avant cela, MyISAM était courant et n’avait pas de transactions résistantes aux crashs. Si votre org garde des hypothèses héritées, elles peuvent être plus anciennes que vos collègues.
  5. Les binlogs MySQL ont été conçus pour la réplication mais sont devenus la colonne vertébrale de la récupération point‑dans‑le‑temps. Ils ne sont pas optionnels si vous tenez à annuler des erreurs humaines.
  6. Percona a popularisé les sauvegardes physiques à chaud pour InnoDB dans les années 2000 avec XtraBackup, car les dumps logiques n’évoluent pas bien et ne préservent pas la disposition physique.
  7. « Copier le datadir » était autrefois un remède populaire pour MySQL. Ça fonctionnait parfois, puis ça a blessé des gens quand file‑per‑table, redo logs et métadonnées sont devenus plus complexes.
  8. SQLite repose sur la sémantique du verrouillage du système de fichiers. Placez‑le sur un système de fichiers étrange ou un montage réseau partagé avec des verrous bizarres et vous pouvez transformer la « base de données simple » en festival de corruption et de performances dégradées.

L’histoire n’est pas de la trivia. C’est la raison pour laquelle votre plan de restauration fonctionne — ou pas — quand la sonnerie du pager retentit.

Primitives de sauvegarde : ce que vous sauvegardez réellement

SQLite : « la base de données est un fichier » (plus parfois deux autres)

SQLite stocke les données dans un seul fichier de base de données principal (souvent app.db). Mais selon le mode de journalisation, vous pouvez aussi avoir :

  • Journal de rollback : app.db-journal (courant en mode DELETE).
  • Fichier WAL : app.db-wal plus le fichier mémoire partagée app.db-shm (en mode WAL).

Sous pression, le piège est d’oublier que « la base de données » peut être trois fichiers et qu’ils doivent être capturés de façon cohérente. La bonne nouvelle : si vous pouvez utiliser le mécanisme de sauvegarde de SQLite ou prendre le snapshot au niveau du système de fichiers correctement, la restauration est généralement simple.

MySQL : un système en fonctionnement avec plusieurs couches de sauvegarde

MySQL a un processus serveur, des redo logs, des undo logs, des fichiers de données, et éventuellement des binlogs. Les sauvegardes se répartissent en deux grandes familles :

  • Sauvegardes logiques (par ex. mysqldump, mysqlpump) : SQL portable, plus lentes à grande échelle, peuvent être partielles, généralement plus faciles à inspecter.
  • Sauvegardes physiques (par ex. Percona XtraBackup, snapshots de système de fichiers) : plus rapides, préservent la structure physique, nécessitent davantage de discipline et de compatibilité.

Sous pression, l’avantage de MySQL est qu’il a été conçu pour la récupération opérationnelle à l’échelle — si vous avez adopté la bonne stratégie de sauvegarde à l’avance. Sinon, il peut se montrer impitoyablement intransigeant.

Blague n°1 : Les sauvegardes sont comme des extincteurs — tout le monde aime l’idée, et personne ne vérifie la pression jusqu’à ce que la cuisine prenne feu.

Restauration SQLite sous pression : le bon, le mauvais, le fichier

Pourquoi SQLite peut être ridiculement simple

Si vous avez une copie cohérente, restaurer SQLite peut être aussi simple que remettre un fichier à sa place. Il n’y a pas de serveur à démarrer, pas de grants utilisateurs à reconstituer, pas de topologie de réplication à démêler.

C’est pourquoi SQLite est apprécié pour les applications mobiles, les périphériques edge, les petits outils internes et les produits « nous avons besoin de quelque chose de fiable mais pas d’un service de base de données complet ». Pour la simplicité au moment de la restauration, c’est difficile à battre : fichier en place, application redémarre, terminé.

Pourquoi SQLite peut être étonnamment difficile

La partie difficile n’est pas la restauration. C’est de savoir si ce que vous avez copié est cohérent.

Si vous avez copié le fichier de base de données pendant que l’application écrivait, vous pouvez obtenir une sauvegarde qui a l’air correcte jusqu’au moment où une requête touche la mauvaise page. Ou jusqu’au premier vacuum. Ou jusqu’à ce que le PDG tente d’exporter un rapport et que vous découvriez que vous avez restauré une base de données logiquement incohérente qui passe des tests rapides superficiels.

Mode WAL : le meilleur ami et l’ennemi de la restauration

Le mode WAL est excellent pour la concurrence. C’est aussi un classique piège à la sauvegarde. En mode WAL, des transactions validées récemment peuvent résider dans -wal jusqu’à ce qu’elles soient checkpointées dans le fichier principal .db. Si vous ne sauvegardez que app.db, vous pouvez restaurer un état plus ancien que ce que vous pensez.

Sous pression, la réussite d’une restauration SQLite dépend souvent d’une question : votre sauvegarde incluait‑elle un snapshot cohérent de .db, -wal et -shm, ou avez‑vous utilisé la méthode de sauvegarde en ligne de SQLite ?

Réalité de la corruption

SQLite est robuste, mais ce n’est pas magique. La corruption provient généralement de l’environnement : stockage défaillant, verrouillage cassé sur des systèmes de fichiers réseau, ou applications qui traitent SQLite comme une base multi‑writer serveur et font leur propre concurrence « créative ».

Quand SQLite se corrompt, votre parcours de récupération ressemble souvent à ceci :

  • Essayez de restaurer depuis une sauvegarde connue bonne.
  • Si aucune sauvegarde valide n’existe, tentez un dump‑and‑reload, une récupération, ou une extraction table par table.
  • Acceptez que certaines données puissent être perdues, et planifiez la réconciliation au niveau applicatif.

Restauration MySQL sous pression : options, bords tranchants, et pourquoi c’est toujours raisonnable

L’avantage de récupération de MySQL : plusieurs chemins

MySQL vous donne des choix : restauration logique, restauration physique, récupération de crash, promotion d’un répliqué, récupération point‑dans‑le‑temps via les binlogs. Sous pression, plusieurs options sont bonnes si vous savez déjà laquelle vous allez utiliser. Sinon c’est la fatigue décisionnelle avec de la syntaxe SQL.

Sauvegardes logiques : fiables, mais le temps peut vous tuer

mysqldump est le ruban adhésif des opérations MySQL. Vous pouvez l’utiliser presque partout, restaurer dans des versions légèrement différentes, et inspecter ce qu’il y a à l’intérieur.

Les inconvénients sont la vitesse et le rayon d’impact opérationnel :

  • Les grosses bases peuvent prendre beaucoup de temps à dumper et encore plus à restaurer.
  • Les restaurations sont bavardes et peuvent saturer l’I/O et la réplication.
  • Sous pression, vous pourriez être tenté de sauter contraintes, triggers ou index « temporairement ». Le temporaire a la fâcheuse habitude de devenir permanent.

Sauvegardes physiques : restaurations rapides, plus de prérequis

Les sauvegardes physiques (comme XtraBackup) peuvent restaurer de grands jeux de données InnoDB beaucoup plus vite que la relecture logique SQL. Elles préservent aussi les structures internes, ce qui aide à des performances prévisibles après restauration.

Le coût est que vous devez respecter la compatibilité de version MySQL, la configuration, et les exigences de l’outil de sauvegarde. La restauration physique peut être une victoire nette — jusqu’au moment où vous découvrez que vous ne l’avez jamais pratiquée et que votre runbook a trois ans.

PITR : la vraie raison pour laquelle MySQL gagne dans bien des contextes en production

Quand quelqu’un exécute une requête destructive, « restaurer la sauvegarde de la nuit dernière » n’est pas un plan, c’est une confession. MySQL avec les binary logs peut récupérer jusqu’à un timestamp ou une frontière de transaction spécifique. C’est important.

SQLite peut faire des choses proches du PITR si vous expédiez des segments WAL ou faites des snapshots fréquents, mais ce n’est pas un flux opérationnel standardisé au sein des organisations de la même manière que le PITR basé sur les binlogs MySQL.

La récupération après crash est intégrée, mais ne la confondez pas avec une sauvegarde

La récupération InnoDB peut rejouer les redo logs et vous ramener à un état cohérent après un crash. Ce n’est pas la même chose qu’avoir une sauvegarde que vous pouvez restaurer sur une autre machine. Sous pression, les équipes confondent souvent ces notions et découvrent que « le serveur ne démarre pas » ne se résout pas par de l’optimisme.

Blague n°2 : « Nous n’avons pas besoin de sauvegardes, nous avons du RAID » revient à dire que vous n’avez pas besoin de ceintures de sécurité parce que votre voiture a quatre pneus.

Verdict sous pression : qui gagne et quand

Si vous avez besoin de la restauration la plus simple possible

SQLite l’emporte quand votre base est petite à moyenne, que les écritures sont contrôlées, et que vous disposez d’un mécanisme de snapshot propre (API de sauvegarde SQLite, ou snapshots de système de fichiers faits correctement). La restauration peut être aussi simple que remplacer un fichier et redémarrer l’application.

Si vous avez besoin de PITR et de flexibilité opérationnelle

MySQL l’emporte quand il faut annuler des erreurs spécifiques, restaurer de larges jeux de données, gérer la concurrence et plusieurs écrivains, et récupérer sans perdre des heures de données. L’écosystème de sauvegarde de MySQL est plus riche, et il est construit autour de la réalité opérationnelle.

Où les équipes se font réellement mal

Les équipes SQLite sont blessées par des hypothèses erronées sur la copie de fichiers, le comportement du WAL, et le verrouillage des systèmes de fichiers.

Les équipes MySQL se font mal en ne choisissant pas de stratégie de sauvegarde (logique vs physique + binlogs) puis en improvisant pendant une panne.

Si vous voulez le système le plus récupérable sous pression, la réponse n’est pas « choisissez MySQL » ou « choisissez SQLite ». La réponse est : choisissez la base qui correspond à votre maturité opérationnelle, puis pratiquez la restauration comme si vous le pensiez vraiment.

Tâches pratiques avec commandes, sorties et décisions (12+)

Ce sont des commandes réelles et exécutables. Chacune inclut ce que signifie la sortie et quelle décision prendre ensuite. Sous pression, vous voulez des commandes qui réduisent l’incertitude.

Tâches SQLite

Tâche 1 : Identifier si la base utilise WAL

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

Sens : La sortie wal signifie que des changements actifs peuvent être dans app.db-wal.

Décision : Les sauvegardes doivent inclure app.db, app.db-wal et app.db-shm, ou utiliser la méthode de sauvegarde en ligne de SQLite.

Tâche 2 : Vérifier si des fichiers WAL existent (et leur taille)

cr0x@server:~$ ls -lh /var/lib/app/app.db*
-rw-r----- 1 app app 512M Dec 30 01:58 /var/lib/app/app.db
-rw-r----- 1 app app  96M Dec 30 02:15 /var/lib/app/app.db-wal
-rw-r----- 1 app app  32K Dec 30 02:15 /var/lib/app/app.db-shm

Sens : Un -wal volumineux suggère de nombreuses transactions validées pas encore checkpointées dans le fichier principal.

Décision : Si vous restaurez à partir de copies de fichiers, restaurez les trois fichiers ensemble à partir du même jeu de snapshots.

Tâche 3 : Prendre une sauvegarde en ligne cohérente avec la commande de backup de SQLite

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

Sens : SQLite crée une sauvegarde cohérente même si la BD est utilisée (elle coopère avec ses propres verrous).

Décision : Préférez ceci au cp quand c’est possible ; cela évite le problème de « copie déchirée ».

Tâche 4 : Vérification d’intégrité sur un fichier SQLite restauré

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

Sens : ok est le meilleur mot de deux lettres que vous lirez ce soir.

Décision : Si ce n’est pas ok, arrêtez et restaurez une autre sauvegarde ou passez en mode sauvetage.

Tâche 5 : Lister rapidement les tables pour confirmer la présence du schéma

cr0x@server:~$ sqlite3 /restore/app.db ".tables"
accounts audit_log invoices sessions users

Sens : Vous avez les tables attendues ; vous ne regardez pas un fichier de base vide ou incorrect.

Décision : Poursuivez avec des tests applicatifs de fumée. Si des tables manquent, vous avez restauré le mauvais fichier ou une sauvegarde partielle.

Tâche 6 : Récupérer à partir d’une base SQLite endommagée en utilisant dump

cr0x@server:~$ sqlite3 /var/lib/app/app.db ".dump" > /tmp/app_dump.sql
Error: database disk image is malformed

Sens : Le fichier est suffisamment corrompu pour qu’un dump complet échoue.

Décision : Essayez de restaurer une sauvegarde antérieure. Si aucune n’existe, tentez des tactiques de sauvetage (outils de récupération au niveau des pages ou extraction des tables intactes), et planifiez une perte partielle des données.

Tâches MySQL

Tâche 7 : Confirmer que la journalisation binaire est activée (vérification capacité PITR)

cr0x@server:~$ mysql -uroot -p -e "SHOW VARIABLES LIKE 'log_bin';"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

Sens : Les binlogs sont activés, donc le PITR est possible si vous avez conservé les fichiers.

Décision : Si OFF, vous ne pouvez pas faire de vrai PITR. Vous restaurerez jusqu’au point de la sauvegarde et accepterez plus de perte de données.

Tâche 8 : Trouver où résident les binlogs et leur format

cr0x@server:~$ mysql -uroot -p -e "SHOW VARIABLES WHERE Variable_name IN ('log_bin_basename','binlog_format');"
+------------------+----------------------+
| Variable_name    | Value                |
+------------------+----------------------+
| binlog_format    | ROW                  |
| log_bin_basename | /var/lib/mysql/binlog|
+------------------+----------------------+

Sens : Vous savez où chercher et que le format est ROW (bon pour la justesse, moins lisible).

Décision : Assurez‑vous que les sauvegardes incluent les binlogs ou qu’ils sont envoyés ailleurs ; ROW signifie que vous utiliserez probablement mysqlbinlog pour la relecture plutôt que d’éditer à la main.

Tâche 9 : Vérifier que la dernière sauvegarde réussie existe et a une taille non triviale

cr0x@server:~$ ls -lh /backups/mysql/full/
-rw-r----- 1 backup backup 8.2G Dec 30 01:00 full.sql.gz
-rw-r----- 1 backup backup 1.4M Dec 30 01:00 full.sql.gz.sha256

Sens : Un dump de plusieurs Go suggère que vous n’avez pas sauvegardé par erreur un schéma vide.

Décision : Vérifiez la somme de contrôle avant la restauration. Si le dump est suspectement petit, arrêtez et enquêtez avant de remplacer la production par une base très vide mais précise.

Tâche 10 : Validation par checksum avant restauration

cr0x@server:~$ sha256sum -c /backups/mysql/full/full.sql.gz.sha256
full.sql.gz: OK

Sens : Votre artefact de sauvegarde a survécu au stockage, au transfert et au temps.

Décision : Si cela échoue, ne le restaurez pas. Trouvez une autre sauvegarde, sinon vous créerez un second incident.

Tâche 11 : Restaurer un mysqldump dans une nouvelle instance (plus sûr que sur place)

cr0x@server:~$ zcat /backups/mysql/full/full.sql.gz | mysql -uroot -p --host=127.0.0.1 --protocol=tcp

Sens : L’absence de sortie signifie généralement succès ; les erreurs s’imprimeront sur stderr.

Décision : Restaurez dans une instance fraîche ou un schéma séparé quand c’est possible, puis basculez. Les restaurations in‑place sont comment on transforme un « mauvais jour » en « opportunité de développement de carrière ».

Tâche 12 : Confirmer les décomptes de lignes pour les tables critiques après restauration

cr0x@server:~$ mysql -uroot -p -e "SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema='app' AND table_name IN ('users','orders');"
+------------+------------+
| table_name | table_rows |
+------------+------------+
| users      |     184233 |
| orders     |     921044 |
+------------+------------+

Sens : Les comptes sont plausibles (pas zéro, pas anormalement bas).

Décision : Si les comptes sont incorrects, vous avez peut‑être restauré la mauvaise sauvegarde, ou le dump a été pris en plein incident et est incomplet.

Tâche 13 : Identifier la position du binlog au moment de la sauvegarde (pour PITR)

cr0x@server:~$ zcat /backups/mysql/full/full.sql.gz | grep -m1 "CHANGE MASTER TO"
-- CHANGE MASTER TO MASTER_LOG_FILE='binlog.003982', MASTER_LOG_POS=19483211;

Sens : Ce dump a enregistré le fichier/position du binlog cohérent avec le snapshot.

Décision : Utilisez cette position comme point de départ pour rejouer les binlogs afin d’atteindre le temps de récupération souhaité.

Tâche 14 : Inspecter les binlogs autour d’une heure suspectée d’une requête fautive

cr0x@server:~$ mysqlbinlog --start-datetime="2025-12-30 01:00:00" --stop-datetime="2025-12-30 02:00:00" /var/lib/mysql/binlog.003982 | head
# at 19483211
#251230  1:00:00 server id 1  end_log_pos 19483315 CRC32 0xa1b2c3d4  Anonymous_GTID  last_committed=0 sequence_number=1 rbr_only=no
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;

Sens : Vous lisez le flux de binlog pour cette fenêtre temporelle.

Décision : Décidez si vous ferez une relecture basée sur le temps (arrêter avant l’erreur) ou si vous filtrerez une instruction spécifique (plus difficile, plus risqué, parfois nécessaire).

Tâche 15 : Rejouer les binlogs pour atteindre un temps cible (PITR)

cr0x@server:~$ mysqlbinlog --start-position=19483211 --stop-datetime="2025-12-30 01:47:00" /var/lib/mysql/binlog.003982 | mysql -uroot -p

Sens : Les transactions entre la position de sauvegarde et l’heure d’arrêt sont appliquées.

Décision : Si vous suspectez une dérive d’horloge, préférez une récupération par position d’arrêt ou basée sur GTID. La récupération basée sur le temps suppose que vos horodatages et fuseaux horaires ne mentent pas.

Tâche 16 : Vérifier les signaux de récupération InnoDB dans les logs

cr0x@server:~$ journalctl -u mysql -n 50 --no-pager
Dec 30 02:11:04 db1 mysqld[2190]: InnoDB: Starting crash recovery from checkpoint LSN=7123489123
Dec 30 02:11:05 db1 mysqld[2190]: InnoDB: 1 transaction(s) which must be rolled back
Dec 30 02:11:06 db1 mysqld[2190]: InnoDB: Crash recovery finished.

Sens : MySQL a effectué la récupération après crash et est revenu proprement.

Décision : Si la récupération boucle ou échoue, arrêtez de redémarrer en force. Envisagez de restaurer depuis une sauvegarde ; des redémarrages répétitifs peuvent aggraver les problèmes disque.

Guide de diagnostic rapide : trouvez le goulot d’étranglement vite

Ceci est la séquence « arrêter de s’agiter et obtenir du signal ». Vous essayez de répondre : qu’est‑ce qui empêche la récupération — artefacts manquants, restauration lente, corruption, ou mauvais objectif de récupération ?

Première étape : prouvez que vous avez les bons artefacts

  • SQLite : Confirmez le mode de journalisation, et confirmez que vous avez un ensemble cohérent de fichiers (.db + -wal + -shm quand applicable).
  • MySQL : Confirmez que la sauvegarde existe, que la checksum passe, et (si PITR) confirmez que les binlogs existent pour la fenêtre temporelle requise.

Deuxième étape : prouvez que la cible de restauration est saine

  • Restaurez d’abord dans un nouveau chemin/une nouvelle instance quand c’est possible.
  • Validez l’espace libre du système de fichiers. Les restaurations échouent tard et brutalement quand les disques se remplissent.
  • Vérifiez la compatibilité de version (surtout pour les restaurations physiques MySQL).

Troisième étape : trouvez si vous êtes limité par l’I/O, le CPU, ou des verrous

  • Symptômes I/O-bound : débit de restauration faible, temps d’attente élevé, pics de latence stockage. Correction : passer à un disque plus rapide, utiliser des snapshots/restauration physique, éviter la décompression sur le même volume lent.
  • Symptômes CPU-bound : décompression saturant les cœurs, checksums lents. Correction : décompression parallèle, rapprocher le calcul des données, ou utiliser une mise en scène pré‑décompressée.
  • Symptômes de verrou (SQLite) : « database is locked », longues latences. Correction : arrêter les writers, utiliser l’API de backup, ou restaurer depuis un snapshot pendant que l’app est arrêtée.

Quatrième étape : décidez clairement l’objectif de récupération

  • Avez‑vous besoin du dernier connu bon (restauration rapide) ou du point‑dans‑le‑temps (précis) ?
  • Récupérez‑vous d’une défaillance matérielle, d’une erreur opérateur, ou d’une corruption de données ? Le chemin diffère.

Erreurs courantes : symptôme → cause racine → correctif

Erreurs SQLite

Symptôme : Après restauration, des écritures récentes manquent.
Cause racine : Mode WAL activé ; la sauvegarde a copié uniquement .db sans -wal.
Correctif : Sauvegarder via sqlite3 .backup ou snapshotter atomiquement tous les fichiers liés ; vérifier en comparant les marqueurs de dernière écriture attendus.
Symptôme : « database disk image is malformed » lors de requêtes ou dump.
Cause racine : Fichier de base corrompu (souvent dû à une copie dangereuse pendant des écritures, corruption du stockage, ou verrouillage cassé sur des montages partagés).
Correctif : Restaurer une sauvegarde connue bonne ; si indisponible, tenter le sauvetage/dump des tables intactes et reconstruire la BD ; déplacer la BD sur un disque local avec verrouillage correct.
Symptôme : « database is locked » pendant la sauvegarde ou au démarrage de l’app.
Cause racine : Transactions écrivantes longues, ou multiples écrivains dans un environnement qui ne se coordonne pas correctement.
Correctif : Mettre les writers en pause ; s’assurer que le mode WAL et les réglages de busy timeout sont sensés ; exécuter les sauvegardes via le mécanisme de backup de SQLite.

Erreurs MySQL

Symptôme : La restauration se termine, mais les données datent de plusieurs heures.
Cause racine : Pas de binlogs conservés (ou binlogs non sauvegardés/expédiés), donc pas de PITR.
Correctif : Activer log_bin, définir une politique de rétention, et sauvegarder ou expédier les binlogs hors hôte. Tester le PITR trimestriellement.
Symptôme : La restauration physique échoue au démarrage de MySQL avec des erreurs InnoDB.
Cause racine : Mismatch de version/config, fichiers redo/undo manquants, ou restauration du datadir sans l’étape de préparation appropriée.
Correctif : Standardiser les versions, enregistrer les configs avec les sauvegardes, et répéter les procédures de restauration physique dans un environnement isolé.
Symptôme : La restauration mysqldump est terriblement lente et bloque la production.
Cause racine : Restauration dans une instance occupée ; relecture mono‑thread ; création d’index lourde pendant le chargement.
Correctif : Restaurer dans une nouvelle instance, puis basculer. Envisager des sauvegardes physiques pour de grands jeux de données. Utiliser des stratégies de chargement sensées (mais ne pas « optimiser » aveuglément).
Symptôme : La relecture PITR provoque des erreurs de clé dupliquée ou des contraintes étranges.
Cause racine : Relecture démarrée à la mauvaise position du binlog, rejouée dans un mauvais état de schéma, ou mélange d’hypothèses GTID/non‑GTID.
Correctif : Enregistrer toujours les coordonnées du binlog au moment de la sauvegarde. Utiliser une base propre de restauration, puis rejouer vers l’avant. Préférer des setups cohérents GTID si vous opérez à grande échelle.

Trois mini‑histoires du terrain en entreprise

Incident n°1 : Une hypothèse erronée (copie de fichier SQLite ≠ sauvegarde)

Une petite équipe produit a déployé un outil interne de workflow d’approbation. Il utilisait SQLite parce que c’était « juste des métadonnées », le trafic était faible, et le déploiement restait très simple. Le plan de sauvegarde était un cron nocturne : cp app.db app.db.$(date) vers un répertoire de sauvegarde puis vers un stockage objet.

Ça a tourné pendant des mois. Personne n’y a pensé. C’est toujours là que les ennuis commencent.

Un matin, l’outil a commencé à rater des approbations avec des erreurs SQL vagues. L’astreinte a restauré la sauvegarde de la nuit précédente. L’application est revenue, mais les approbations manquaient — précisément, le dernier jour de modifications. Tout le monde a blâmé la restauration. Puis l’application. Puis, inévitablement, l’astreinte.

Le vrai problème : la base était en mode WAL, et le cron ne copiait que app.db. La « sauvegarde » était cohérente au sens où c’était un fichier SQLite valide. Elle était aussi dépourvue des transactions validées résidant dans le WAL au moment de la copie. La copie nocturne avait fidèlement sauvegardé une vue plus ancienne de la réalité.

Le correctif était ennuyeusement simple : passer les sauvegardes à la commande de backup en ligne de SQLite (ou snapshotter l’ensemble des fichiers WAL atomiquement), ajouter une vérification d’intégrité après la sauvegarde, et ajouter un test de restauration. Soudain la restauration signifiait « restaurer », pas « restaurer‑à‑peine ».

Incident n°2 : Une optimisation qui s’est retournée contre eux (astuces de vitesse de restauration MySQL)

Une entreprise SaaS de taille moyenne exécutait des dumps logiques MySQL nightly. Les restaurations étaient lentes, alors quelqu’un a proposé un classique : désactiver les checks de clés étrangères et d’unicité pendant la restauration, et pousser des réglages bulk. Ça a marché en staging. En sandbox dev. Ça a même marché une fois en production, et c’est ainsi que les mauvaises idées gagnent de l’ancienneté.

Puis ils ont eu un vrai incident : un primaire a lâché et ils devaient reconstruire vite. Ils ont restauré le dump avec les contraintes désactivées et remis le service. Les métriques semblaient normales. L’incident a été clos.

Deux jours plus tard, les tickets support ont explosé. Le système avait des lignes orphelines et des associations dupliquées dans des cas limites. Pas partout. Juste assez pour coûter cher et être humiliant. L’« optimisation » avait permis à des états intermédiaires incohérents de s’insinuer parce que le processus de restauration n’était pas identique à l’opération normale, et les écritures applicatives ont repris avant que toutes les contraintes ne soient réactivées et vérifiées.

Le postmortem a été douloureux mais utile : les restaurations doivent être traitées comme des changements en production avec des portes de validation. Ils sont passés à des restaurations dans une nouvelle instance, lancent des vérifications d’intégrité et des jobs de réconciliation applicative, puis ne basculent qu’après. Ils ont aussi réévalué les sauvegardes physiques pour réduire le temps de restauration sans sacrifier la correction.

Incident n°3 : La pratique ennuyeuse mais correcte qui a sauvé la journée (PITR MySQL avec binlogs)

Une équipe d’entreprise exécutait MySQL avec des backups complets hebdomadaires, des incréments quotidiens et un shipping continu des binlogs. Pas glamour. Ça demandait de la discipline : réglages de rétention, surveillance des trous de binlogs, drills de restauration périodiques, et l’art social d’insister pour « oui, on teste encore les restaurations ».

Un après‑midi, un ingénieur a lancé un script de nettoyage de données prévu pour l’environnement de staging. Il s’est connecté à la prod. Le script n’était pas malveillant ; juste trop confiant. Il a supprimé des lignes dans une table de grande valeur, et l’application a propagé l’absence de données dans les caches et systèmes en aval.

Ils ont déclaré un incident et gelé les écritures. Puis ils ont exécuté un runbook pratiqué : restaurer le dernier full backup dans une nouvelle instance, appliquer les backups incrémentaux, et rejouer les binlogs jusqu’à un timestamp juste avant le début du script. Le service est revenu avec une perte minimale de données, et l’équipe a pu ensuite réconcilier les quelques minutes d’écritures qui avaient été volontairement mises en pause pendant la récupération.

Ce qui les a sauvés n’était pas du génie. C’était un système prévisible : coordonnées de sauvegarde connues, continuité des binlogs, et l’habitude de répéter. Quand l’adrénaline monte, il y a moins de réflexion et plus d’exécution.

Listes de contrôle / plan pas à pas

SQLite : plan de récupération pas à pas

  1. Arrêter les writers (ou mettre l’app en mode maintenance). SQLite gère la concurrence, mais la récupération n’est pas le moment de négocier des verrous avec une charge en direct.
  2. Identifier le mode de journalisation et confirmer quels fichiers doivent être restaurés.
  3. Restaurer en ensemble : .db plus les fichiers liés au WAL si applicable, depuis le même snapshot.
  4. Exécuter des vérifications d’intégrité et des contrôles basiques de schéma.
  5. Test de fumée applicatif avec des requêtes parcourant des chemins de données réels, pas seulement « SELECT 1 ».
  6. Capturer l’artefact cassé pour analyse ultérieure. Ne l’écrasez pas. Les incidents coûtent cher ; tirez‑en des apprentissages.

MySQL : plan de récupération pas à pas (logique + PITR)

  1. Définir le point de récupération : dernier bon moment ou « juste avant la requête fautive ». Notez‑le.
  2. Geler les écritures si l’objectif est la correction (surtout pour le PITR). On ne peut pas poursuivre une cible qui bouge sans fin.
  3. Valider l’artefact de sauvegarde (checksum, taille cohérente).
  4. Restaurer dans une nouvelle instance quand possible. Les restaurations in‑place sont pour les urgences dans les urgences.
  5. Appliquer les binlogs depuis la position enregistrée jusqu’au timestamp/position cible.
  6. Valider les données : comptages, invariants critiques, et vérifications applicatives.
  7. Bascule (DNS, load balancer, chaînes de connexion), puis surveiller les taux d’erreur et la réplication si applicable.
  8. Hygiène post‑restauration : s’assurer que la rétention des binlogs reprend, que les sauvegardes continuent, et que l’ancienne instance est préservée assez longtemps pour comparaison forensique.

MySQL : plan de récupération pas à pas (état d’esprit restauration physique)

  1. Confirmer la compatibilité version/config avec la sauvegarde.
  2. Provisionner un stockage propre avec assez d’espace pour les données + marge.
  3. Préparer la sauvegarde (appliquer les logs) selon la procédure de votre outil.
  4. Restaurer le datadir et régler propriétaire/permissions correctement.
  5. Démarrer MySQL et surveiller les logs jusqu’à ce qu’il soit totalement prêt.
  6. Valider avec des contrôles correspondant à vos invariants métier.

FAQ

1) SQLite est‑il « plus facile à restaurer » parce que c’est un seul fichier ?

Parfois. Si vous avez un snapshot cohérent, la restauration est triviale. Si vous l’avez copié de façon dangereuse ou oublié les fichiers WAL, la récupération devient de l’archéologie.

2) SQLite peut‑il faire une restauration point‑dans‑le‑temps comme MySQL ?

Pas comme un flux opérationnel standardisé. Vous pouvez approcher le PITR avec des snapshots fréquents ou l’expédition des WAL, mais c’est sur mesure et facile à rater sous pression.

3) Est‑ce que cp app.db est parfois une sauvegarde SQLite valide ?

Seulement si vous pouvez garantir que la base n’est pas écrite pendant la copie, ou si vous prenez un snapshot de système de fichiers crash‑consistent incluant les fichiers liés au WAL. Sinon, utilisez le mécanisme de backup de SQLite.

4) Pour MySQL, mysqldump suffit‑il ?

Pour des jeux de données petits à moyens et pour la portabilité, oui. Pour de grands volumes ou des RTO stricts, vous voudrez des sauvegardes physiques plus les binlogs. Et vous devrez pratiquer les restaurations.

5) Quel est le plus gros piège de récupération MySQL dans la vraie vie ?

Penser que vous avez le PITR alors que non. Binlogs désactivés, binlogs non conservés, ou binlogs non expédiés hors‑hôte transforment « annuler l’erreur » en « restaurer la nuit dernière et s’excuser ».

6) Si MySQL a une récupération après crash, pourquoi ai‑je besoin de sauvegardes ?

La récupération après crash aide une instance unique à récupérer d’un arrêt non propre. Elle ne vous protège pas contre la perte de disque, l’erreur opérateur, le ransomware, ou le besoin de restaurer à hier.

7) Lequel est le plus susceptible de se corrompre ?

Les deux peuvent se corrompre si le stockage trompe. SQLite est plus sensible au verrouillage du système de fichiers et aux schémas de copie dangereuse. MySQL peut aussi se corroder, mais son écosystème et ses pratiques opérationnelles tendent à détecter les problèmes plus tôt — si vous surveillez et validez.

8) Quel est le chemin de restauration le plus rapide et sûr pour chacun ?

SQLite : restaurer un snapshot connu bon de la BD (et l’ensemble WAL si applicable), exécuter PRAGMA integrity_check, redémarrer l’app. MySQL : restaurer depuis une sauvegarde physique sur une instance fraîche, puis appliquer les binlogs jusqu’au point cible.

9) Dois‑je garder SQLite sur un stockage réseau ?

Évitez‑le sauf si vous êtes sûr des sémantiques de verrouillage du système de fichiers et de son comportement sous contention. SQLite est plus heureux sur des disques locaux. Les montages réseau sont l’endroit où le « simple » devient compliqué.

10) À quelle fréquence devons‑nous tester les restaurations ?

Au moins trimestriellement pour les systèmes critiques, et après tout changement majeur de version/config. Si vous n’avez jamais restauré avec succès, vous n’avez pas de sauvegardes — vous avez du stockage.

Conclusion : étapes pratiques suivantes

Si vous voulez que la récupération soit facile sous pression, concevez‑la :

  • Pour SQLite : arrêtez les copies de fichiers occasionnelles. Utilisez le mécanisme de backup de SQLite ou des snapshots cohérents, et tenez compte systématiquement du WAL. Ajoutez des vérifications d’intégrité après sauvegarde et après restauration.
  • Pour MySQL : choisissez une stratégie : logique pour la portabilité, physique pour la vitesse, et binlogs pour le PITR. Ensuite pratiquez les restaurations dans un environnement propre jusqu’à ce que le runbook cesse d’être une fiction aspiratoire.
  • Pour les deux : validez automatiquement les sauvegardes, conservez plusieurs générations, et exécutez au moins un vrai drill de restauration par trimestre. Ce n’est pas le moment de découvrir que votre sauvegarde est cassée quand vos clients l’ont déjà appris.

La récupération n’est pas une fonctionnalité à ajouter plus tard. C’est une habitude que vous construisez délibérément — ou que vous paierez en sueur à 02:17.

← Précédent
Ubuntu 24.04 : les VLAN ne fonctionnent pas — le paramètre bridge que la plupart oublient
Suivant →
EPYC : comment AMD a transformé les serveurs en vitrine

Laisser un commentaire