J'utilise Borg pour les sauvegarde de mes machines depuis un bon moment maintenant, et j'en suis totalement satisfait. Cependant, il y a un cas d'utilisation que je n'avais pas encore rencontré : la corruption d'un dépôt de sauvegarde.

C'est maintenant chose faite, l'un de mes dépôts ayant subi la perte d'un fichier cette semaine. Cet article décrit la manière dont j'ai détecté le problème, les méthodes permettant de limiter une catastrophe, ainsi que les actions à entreprendre pour réparer le contenu du dépôt.

Détecter le problème et déterminer sa cause

À la fin de chaque sauvegarde, je reçois un rapport par email contenant les statistiques de la nouvelle sauvegarde, ainsi que les statistiques de la suppresion éventuelle de vielles archives selon ma politique de rétention.

Une règle de filtrage me permet de ranger automatiquement les emails de sauvegarde dans un répertoire de mon client email, mais uniquement si le mot success est présent dans l'objet. J'ai donc assez facilement repéré qu'il y avait un problème lorsque j'ai commencé à recevoir un email d'échec toutes les heures, ma boite de réception étant toujours vide habituellement.

Plutôt qu'un rapport de sauvegarde, ces emails contenaient un traceback python, dont la ligne la plus intéressante est OSError: [Errno 5] Input/output error. Cette erreur apparaît quasi-exclusivement lorsqu'une erreur matérielle se produit sur le périphérique de stockage. Pourtant, après une analyse rapide, ni la commande fsck, ni la commande smartctl -t short n'ont détecté d'erreur, alors que la sortie de la commande dmesg montrait énormément d'erreurs de lecture et d'écriture. J'ai alors lancé un test long avec smartctl -t long, et celui-ci s'est terminé sur une erreur de lecture à moins de 30% du test, confirmant que le disque dur était en train de lâcher.

Déterminer l'étendue des dégâts

Une fois la nature du problème déterminée, j'ai voulu savoir quelles données étaient impactées. Cette machine comportant principalement des dépôts de sauvegarde, j'ai commencé par utiliser la commande borg check <RepoPath>, afin de vérifier l'intégrité des différents dépôts de sauvegardes présents sur ce disque. Dans mon cas, seul le dépôt provoquant les emails d'échec a présenté une erreur, renvoyant la même erreur que lors de la création d'une archive (Input/output error). Cela provoquait d'ailleurs le crash de Borg lors de la vérification.

Note: Comme toutes les autres, la commande borg check doit être lancée sur une machine capable de déchiffrer le contenu. Pour un dépôt chiffré avec la méthode keyfile, il n'est donc pas possible de l'exécuter sur le serveur de sauvegarde s'il ne dispose de la clé de chiffrement.

Mon premier réflexe a donc été de créer deux copies de ce dépôt. La première sera conservée telle quelle, afin d'utiliser le moins possible le répertoire touché par l'erreur. La seconde est utilisée pour exécuter des opérations de réparation. En cas d'erreur lors de la réparation (bug ou fausse manipulation), ou pour tenter d'autres méthodes, il suffira alors de redupliquer la première copie et de recommencer. Lors de la copie du répertoire, l'erreur Input/output error est de nouveau apparue sur un des fichiers, pour lequel seuls 18 Mo sur 265 ont pu être copiés.

Les données perdues sont donc uniquement celles présentes dans ce fichier, les autres ayant été copiés sans erreur. Cependant, Borg utilisant un mécanisme de déduplication, les données présentes dans un fichier peuvent être utilisées par plusieurs archives, voire constituer de multiples archives entières.

Heureusement, même s'il manque des données, le dépôt complet n'est pas rendu inutilisable pour autant. Les données présentes dans le fichier perdu ont par contre bien disparu, définitivement.

Réparer le dépôt autant que possible

La commande borg check utilisée précédemment possède un paramètre --repair. Son utilisation provoque l'affichage d'un avertissement pour prévenir que cette commande est considérée comme expérimentale. Cela confirme la nécessité de travailler sur une copie du dépôt endommagé : En cas de bug ou d'erreur lors de la réparation, on peut toujours repartir de la copie non modifiée et recommencer.

La procédure complète permettant de réparer un dépôt se déroule en trois étapes :

  • Tout d'abord, une première exécution de la commande borg check --progress --verbose --repair <RepoPath> permet de rétablir la cohérence de la structure générale du dépot. Lors de cette étape, tous les blocs de données perdus sont remplacés par des zéros, mais les métadonnées associées sont conservées. Aucune donnée n'est récupérée à ce stade, mais le dépôt est alors de nouveau utilisable sans rencontrer d'erreur.
  • La seconde étape consiste à lancer la création d'une nouvelle archive, comme lors de n'importe quelle sauvegarde. Cette étape permet de créer une nouelle sauvegarde complète et cohérente basée sur les données source. Si le dépôt contient plusieurs archives différentes (par exemple la sauvegarde séparée de plusieurs répertoires au sein d'un même dépôt), il faudra lancer une sauvegarde pour chaque.
  • Enfin, une seconde exécution de la commande borg check --progress --verbose --repair <RepoPath> permet de repeupler certains blocs de données remplacés par des zéros lors de la première étape. En effet, les métadonnées ayant été conservées, Borg est capable de déterminer quels blocs de données générés par la nouvelle sauvegarde créée sont identiques à ceux des anciennes. Les données perdues d'anciennes sauvegardes peuvent alors être complétées.

Note : Les paramètres --progress et --verbose ne sont pas indispensables, mais ils permettent de conserver un historique des modifications appliquées lors de la réparation. Je conseille d'ailleurs de conserver la sortie de toutes les commandes utilisées, afin de pouvoir retrouver ultérieurement la liste des archives et des fichiers touchés à chaque étape.

Après ces opérations, le dépôt est de nouveau cohérent, et une partie de l'historique a été réparée. Cependant, certaines données manquent toujours :

  • Les données perdues qui ne sont plus présentes dans la source des sauvegardes ne sont pas reconstituées.
  • Les archives dont les méta-données ont été totalement perdues sont supprimées du dépôt. En effet, Borg n'est alors pas capable de savoir quel était leur contenu. Cela a concerné 42 archives sur 1338 dans mon cas.

Vérifier les données réparées

Une fois la réparation terminée, il est nécessaire de vérifier la totalité du contenu du dépôt. Cette étape permet de s'assurer que les archives et fichiers ont été correctement réparés, mais aussi que d'autres blocs de données n'ont pas été altérés silencieusement par la corruption initiale. En effet, à cause de la déduplication, un bloc de données endommagé dans le dépôt pourrait impacter les futures sauvegardes contenant les mêmes informations, puisqu'elles ne seront alors pas retransmises.

Pour cela, il est possible de lancer la commande borg check --verify-data <RepoPath>. En plus de vérifier que les données sont présentes et que les méta-données sont cohérentes, cette commande vérifie l'intégrité des données présentes dans le dépôt complet. L'exécuter sur le dépôt entier peut par contre être très long, puisqu'il sera nécessaire de déchiffrer et décompresser la totalité des données, mais cela me semble nécessaire dans ce cas.

Limiter les risques de pertes de données

La perte d'un fichier du dépôt peut impacter plusieurs archives, et faire perdre définitivement une partie des données sauvegardées, quelle que soit la politique de rétention. C'est la principale faiblesse de la déduplication. La seule solution pour limiter ce risque consiste en la réalisation de plusieurs sauvegardes indépendantes, rendant la perte totale ou partielle d'une sauvegarde moins critique.

J'insite bien sur la nécessité que les deux sauvegardes soient indépendantes, afin de s'assurer que, même si l'un des dépôts est totalement inutilisable, il reste au moins une sauvegarde complète en bon état. En effet, synchroniser une sauvegarde sur une autre machine répliquerait aussi la perte de données, ce qui ne serait d'aucun secours lors d'un incident comme celui qui est survenu sur mon serveur.

De plus, il ne faut pas oublier qu'un crash de la machine source est toujours possible pendant la durée des opérations de réparation. Même si le risque est faible dans certains cas, l'absence de sauvegarde en bon état à ce moment serait inévitablement synonyme d'une perte de données définitive, surtout si la tâche de sauvegarde est elle aussi stoppée durant cette période.

Réintégrer des données disparues de l'historique

Pour aller plus loin dans la réparation du dépôt, il est possible de combler certains blocs de données perdus en utilisant l'historique d'une autre sauvegarde. Le principe est ici de réintégrer dans le dépôt des blocs de données identiques à ceux qui ont été perdus et remplacés par des zéros pendant la réparation, comme lors de la seconde étape de la procédure standard de réparation.

Par exemple, si le fichier path/important-data est signalé comme endommagé dans une vieille archive du dépôt partiellement réparé par la commande borg check, il est possible de suivre cette procédure :

$ borg mount <OtherRepoPath> <MountPointPath>
$ borg create [--arguments] <DamagedRepoPath>::<TempArchiveName> <MountPointPath>/<ArchiveName>/path/important-data
$ borg check --repair <DamagedRepoPath>
$ borg delete <DamagedRepoPath>::<TempArchiveName>

Note : Si plusieurs fichiers doivent être restaurés de cette manière, il est possible de les mettre tous dans l'archive temporaire, ou de créer plusieurs archives temporaires avant de lancer la commande de réparation. Il est aussi possible de copier l'intégralité de l'archive de l'autre dépôt, en donnant simplement le répertoire racine de cette archive comme source, bien que cette opération soit évidemment coûteuse.

Note : L'archive <ArchiveName> utilisée doit bien évidemment avoir été créée à une date proche pour maximiser la quantité de données identiques à celles de l'archive à réparer.

Note : Il est important que les données chargées par cette nouvelle archive soient identiques à celles qui étaient présentes dans celle que l'ont veut réparer. Cependant, des paramètres de chiffrement et de compression différents n'empêcheront pas Borg de reconstituer la vieille archive.

Note : Pour gagner du temps, il est possible de restreindre la réparation aux archives contenant les fichiers récupérés, plutôt que réexécuter le processus sur tout le dépôt à chaque fois.

Prévenir plutôt que guérir

N'ayant jamais eu d'erreur de disque dur auparavant, je n'étais pas bien préparé à ce genre d'incident. J'ai bien telegraf qui remonte des informations depuis S.M.A.R.T., mais jusqu'à présent, je ne savais pas quels attributs étaient importants ou intéressants à surveiller, malgré quelques recherches sur Internet.

En regardant les informations remontées dans les journaux système du serveur, j'ai découvert que des erreurs y apparaissaient depuis plusieurs semaines indiquant un nombre de secteurs illisibles, en attente de remplacement. À partir de cette information, j'ai regardé les valeurs présentes dans ma base de données de supervision, et j'ai sélectionné trois attributs S.M.A.R.T. à afficher dans mes graphiques :

  • Reallocated_Sector_Ct (ID 5) : Nombre de secteurs réalloués, si le système réussit à lire les données.
  • Current_Pending_Sector (ID 197) : Nombre de secteurs défectueux en attente de réallocation.
  • Offline_Uncorrectable (ID 198) : Nombre de secteurs dont la correction a échoué lors d'un test automatique.

L'historique montre que les premiers secteurs défectueux sont apparus 28 jours avant que je ne détecte le problème. Avec des alertes correctement paramétrées, j'aurais donc eu largement le temps d'agir avant de perdre des données.

Conclusion

Après toutes ces opérations, le dépôt qui a été endommagé est de nouveau pleinement utilisable et ne contient plus d'archive incomplète. Quelques archives ont totalement disparu, mais la fréquence de création des archives ainsi que la présence de la seconde sauvegarde indépendante me permettent de limiter le risque de perdre définitivement des données.

Bien évidemment, le disque défaillant a été abandonné et les données ont toutes été déplacées vers un nouveau disque dur.

Pour finir, cette mésaventure m'a permis de confirmer que Borg est un outil fiable et robuste, malgré que la présence d'une seconde sauvegarde soit indispensable pour garantir la sécurité des données. L'ajout d'un mécanisme de correction d'erreur est envisagée depuis plusieurs années, mais la méthode à utiliser n'est pas encore définie. En attendant une décision, le mainteneur principal préfère ne pas ajouter d'implémentation partielle de cette fonctionnalité, pour éviter que les utilisateurs ne soient victimes d'un faux sentiment de sécurité.