Question répertoire rsync pour que toutes les modifications apparaissent de manière atomique


Je fais des miroirs nocturnes et hebdomadaires de référentiels fréquemment utilisés pour le réseau local. À quelques reprises, quelqu'un a essayé de faire une mise à jour alors que la procédure rsync était en cours et avait échoué car les fichiers attendus n'y étaient pas encore complets.

Est-il possible de faire un rsync tel que tout les fichiers modifiés apparaissent-ils uniquement avec les noms corrects à la fin? Je sais que rsync utilise des fichiers temporaires .hidden lorsque chaque transfert est en cours, mais puis-je reporter les renommage jusqu'à ce qu'il soit terminé d'une manière ou d'une autre?

Alternativement, il semble que je pourrais utiliser l'option --backup pour déplacer toutes les modifications dans un répertoire et les déplacer de manière atomique après, mais je voudrais que la fonctionnalité fonctionne à l'inverse de ce qu'elle est maintenant.

Je suis sur Linux pour ce que ça vaut.


7
2017-12-07 17:23


origine




Réponses:


Vous pouvez utiliser le --link-dest= option. Fondamentalement, vous créez un nouveau dossier, tous les fichiers sont liés au nouveau. Lorsque tout est terminé, vous pouvez simplement échanger les noms de dossiers et supprimer l'ancien.

Il est impossible de faire cela à 100% atomique sous Linux car il n’est pas supporté par le noyau / VFS. Toutefois, l’échange des noms n’est en réalité qu’à 2 appels système, il faut donc moins d’une seconde pour le compléter. Il est possible uniquement sur Darwin (MAC / OSX) avec l'appel système échangé des données sur les systèmes de fichiers HFS.


4
2017-12-07 17:31





Je fais quelque chose de similaire avec rsync sauvegardes [sur le disque] et j'ai rencontré le même problème en raison d'un démon mettant à jour les fichiers pendant l'exécution de la sauvegarde.

Contrairement à beaucoup de programmes, rsync a beaucoup codes d'erreur différents [voir la page de manuel en bas]. D'intérêt sont deux:

23 - transfert partiel dû à une erreur
  24 - transfert partiel dû à la disparition de fichiers sources

Lorsque rsync effectue un transfert et rencontre l'une de ces situations, cela ne s'arrête pas immédiatement. Il saute et continue avec les fichiers qu'il pouvez transfert. À la fin, il présente le code de retour.

Donc, si vous obtenez l'erreur 23/24, relancez simplement rsync. Les exécutions suivantes iront beaucoup plus rapidement, généralement en ne transférant que les fichiers manquants de l’exécution précédente. Finalement, vous obtiendrez (ou devriez obtenir) une nouvelle série.

Pour être atomique, j'utilise un répertoire "tmp" lors du transfert. Ensuite, quand rsync run est propre, je le renomme [atomiquement] en <date>

J'utilise aussi le --link-dest option, mais je l’utilise pour conserver des sauvegardes delta (par exemple, --link-dest=yesterday pour tous les jours)

Bien que je ne l'utilise pas moi-même, le --partial-dir=DIR peut empêcher les fichiers cachés d’encombrer le répertoire de sauvegarde. Assurez-vous que DIR se trouve sur le même système de fichiers que votre répertoire de sauvegarde afin que les renommés soient atomiques.

Pendant que je faisais cela en Perl, j’ai écrit un script qui résume ce que j’ai dit avec un peu plus de détail / précision pour votre situation particulière. C'est dans la syntaxe de tcsh-like, [non testé et un peu approximatif], mais traitez-le comme un pseudo-code pour écrire votre propre bash, perl, python script que vous choisissez. Notez qu'il n'y a aucune limite sur les tentatives, mais vous pouvez l'ajouter assez facilement, selon vos souhaits.

#!/bin/tcsh -f
# repo_backup -- backup repos even if they change
#
# use_tmp -- use temporary destination directory
# use_partial -- use partial directory
# use_delta -- make delta backup

# set remote server name ...
set remote_server="..."

# directory on server for backups
set backup_top="/path_to_backup_top"
set backup_backups="$backup_top/backups"

# set your rsync options ...
set rsync_opts=(...)

# keep partial files from cluttering backup
set server_partial=${remote_server}:$backup_top/partial
if ($use_partial) then
    set rsync_opts=($rsync_opts --partial-dir=$server_partial)
endif

# do delta backups
if ($use_delta) then
    set latest=(`ssh ${remote_server} ls $backup_backups | tail -1`)

    # get latest
    set delta_dir="$backup_backups/$latest"

    if ($#latest > 0) then
        set rsync_opts=($rsync_opts --link-dest=${remote_server}:$delta_dir)
    endif
endif

while (1)
    # get list of everything to backup
    # set this to whatever you need
    cd /local_top_directory
    set transfer_list=(.)

    # use whatever format you'd like
    set date=`date +%Y%m%d_%H%M%S`

    set server_tmp=${remote_server}:$backup_top/tmp
    set server_final=${remote_server}:$backup_backups/$date

    if ($use_tmp) then
        set server_transfer=$server_tmp
    else
        set server_transfer=$server_final
    endif

    # do the transfer
    rsync $rsync_opts $transfer_list $server_transfer
    set code=$status

    # run was clean
    if ($code == 0) then
        # atomically install backup
        if ($use_tmp) then
            ssh ${remote_server} mv $backup_top/tmp $backup_backups/$date
        endif
        break
    endif

    # partial -- some error
    if ($code == 23) then
        continue
    endif

    # partial -- some files disappeared
    if ($code == 24) then
        continue
    endif

    echo "fatal error ..."
    exit(1)
end

4
2017-12-07 23:22



Vous semblez avoir un vagabond (ou manquant) '"' dans set backup_backups=$backup_top/backups" - David C. Rankin
@ DavidC.Rankin Bonjour, David. Oui, corrigé. [mais je me suis qualifié en tant que "rugueux" ;-)]. Mais merci d'avoir suivi le lien sous ma réponse SO. J'ai déjà fait d'autres liens de ce type auparavant, mais vous êtes le premier à fournir une confirmation positive que quiconque les suit effectivement :-) - Craig Estey
Oh oui, pas de problème. J'étais en fait curieux de savoir comment vous avez configuré vos incrémentaux. J'ai utilisé rsync pour gérer mes sauvegardes au bureau (enfin ... depuis 2001 (ou 2)), et je regarde toujours les différentes façons dont les gens gèrent les leurs. Je l'aime. - David C. Rankin
@ DavidC.Rankin C'est assez similaire. Pour plusieurs hôtes: set backup_backups="$backup_top/backups/<host_to_backup>". Le script est exécuté sur cet hôte. Il fait d'abord tune2fs -l et utilise "Etat du système de fichiers" pour voir si le système de fichiers contient des erreurs (par exemple, les besoins fsck) et refuse de courir si oui. Le nom de chaque lecteur de sauvegarde est une couleur (par exemple, cuivre, indigo, etc.). Je tire un lanceur sur chaque système et ils fixent une heure (par exemple, 10h09 -> 10h15) afin qu'ils se déclenchent tous à la même heure (donne au propriétaire le temps de remonter sans heure). Ainsi, lorsque tout est terminé, chaque système a exactement le même horodatage pour la sauvegarde. - Craig Estey
@ DavidC.Rankin Le lanceur lance rsync dans une fenêtre xterm avec une couleur de fond de la couleur du lecteur. C'est joli, mais j'ai deux systèmes et quatre lecteurs bkup, donc si je dis bkup all sys sur tous les lecteurs, cela aide. L'horodatage commun permet d'obtenir "l'état du monde" à l'heure X. Je ne le fais pas, mais la rotation de plusieurs lecteurs vers un coffre-fort hors site. Effectuez une sauvegarde [de tous les systèmes] sur un lecteur donné pour un jour donné [rotation]. Finalement, les lecteurs ont comme N mois de deltas. De temps en temps, cherchez les plus vieux pour l’espace. J'utilise des clés USB WD-MyBook (4 To), donc je suis parti un an sans avoir besoin de gagner de la place. - Craig Estey


Je ne sais pas si cela va vous aider, mais ...

Si cela ne vous dérange pas de copier l’ensemble des données à chaque fois et si vous pouvez utiliser des liens symboliques pour faire référence au répertoire cible, vous devriez être capable de tout rsync dans un répertoire temporaire puis d’échanger (Renommer()) les anciens et les nouveaux liens symboliques atomiquement, comme suit:

% mkdir old_data new_data
% ln -s old_data current
% ln -s new_data new
% strace mv -T new current

qui court

rename("new", "current")                = 0

et donne

current -> new_data

Même pour que cela fonctionne, tout client essayant de lire à partir de cette configuration devrait cd dans le répertoire référencé par le lien symbolique avant toute tentative de lecture, sinon ils risquent de charger certaines parties du code / données de l'ancienne copie et d'autres de la nouvelle.


1
2017-12-07 19:25



J'utilise un algorithme similaire (copie vers un nouveau lien symbolique directowy + change nommé actuel) avec mon script d'installation d'applications Web PHP, y compris sur des serveurs de production. C’est une solution qui permet un temps d’immobilisation minimal et une procédure totalement atomique. - sam_pan_mariusz


Le miroir se synchronise-t-il automatiquement? cron tâche ou similaire)? Si c'est le cas, vous utilisez probablement un utilisateur de système d'exploitation dédié à cette fin, ai-je raison? La solution pourrait donc être, au lieu de simplement copier:

  1. Définir les autorisations du répertoire de destination rsync sera en mesure d'y accéder.
  2. Procédez à la synchronisation.
  3. Modifiez les autorisations de la cible (sans condition) afin que les autres puissent y accéder à nouveau.

L'inconvénient est que pendant le processus de synchronisation (vous ne savez pas combien de temps cela prend), le répertoire cible ne sera pas accessible. Vous devez décider vous-même si tout va bien ici.


1
2017-12-07 19:52