Si Apache écrit un fichier quelconque à un endroit et n'a pas terminé de l'écrire puis rsync
démarre, rsync
copiera tout ce qui est assis là.
Cela signifie que si Apache traite un fichier de 5 Mo, seuls 2 Mo sont écrits et rsync
démarre, le fichier partiel de 2 Mo sera copié. Ainsi, ce fichier semblerait être "corrompu" sur le serveur de destination.
Selon la taille des fichiers que vous utilisez, vous pouvez utiliser le --inplace
option en rsync
pour faire ce qui suit :
Cette option modifie la manière dont rsync transfère un fichier lorsque les données du fichier doivent être mises à jour :au lieu de la méthode par défaut consistant à créer une nouvelle copie du fichier et à la mettre en place lorsqu'elle est terminée, rsync écrit à la place les données mises à jour directement dans le fichier de destination.
L'avantage de ceci est que si un fichier de 5 Mo n'a que 2 Mo copiés lors de la première exécution, la prochaine exécution reprendra à 2 Mo et continuera à copier le fichier jusqu'à ce que les 5 Mo soient en place.
L'inconvénient est que cela pourrait créer une situation dans laquelle quelqu'un accède au serveur Web pendant la copie d'un fichier, puis verrait un fichier partiel. A mon avis rsync
fonctionne mieux dans son comportement par défaut de mise en cache d'un fichier "invisible" puis de le mettre en place immédiatement. Mais --inplace
est bon pour les scénarios où les fichiers volumineux et les contraintes de bande passante peuvent empêcher la copie facile d'un fichier volumineux à partir de la case départ.
Cela dit, vous déclarez ceci; l'accent est mis sur moi :
Toutes les cinq minutes a cron exécuté rsync…
Donc, je suppose que vous avez un script bash en place pour gérer ce travail cron ? Eh bien, le truc est rsync
est assez intelligent pour ne copier que les fichiers qui doivent être copiés. Et si vous avez un script qui s'exécute toutes les 5 minutes, il semble que vous essayez d'éviter d'avoir rsync
marcher l'un sur l'autre si ça va plus vite. Cela signifie que si vous l'exécutez toutes les minutes, il y a un risque qu'un ou plusieurs des rsync
les processus seraient toujours en cours d'exécution en raison de la taille du fichier ou de la vitesse du réseau et le processus suivant serait simplement en concurrence avec lui ; une condition de course.
Une façon d'éviter cela est d'envelopper tout votre rsync
commande dans un script bash qui recherche un verrou de fichier ; ci-dessous est un framework de script bash passe-partout que j'utilise pour des cas comme celui-ci.
Notez que certaines personnes recommanderont d'utiliser flock
mais depuis flock
n'est pas installé sur certains systèmes que j'utilise - et je saute souvent entre Ubuntu (qui l'a) et Mac OS X (qui n'en a pas) - j'utilise ce framework simple sans réel problème :
LOCK_NAME="MY_GREAT_BASH_SCRIPT"
LOCK_DIR='/tmp/'${LOCK_NAME}.lock
PID_FILE=${LOCK_DIR}'/'${LOCK_NAME}'.pid'
if mkdir ${LOCK_DIR} 2>/dev/null; then
# If the ${LOCK_DIR} doesn't exist, then start working & store the ${PID_FILE}
echo $$ > ${PID_FILE}
echo "Hello world!"
rm -rf ${LOCK_DIR}
exit
else
if [ -f ${PID_FILE} ] && kill -0 $(cat ${PID_FILE}) 2>/dev/null; then
# Confirm that the process file exists & a process
# with that PID is truly running.
echo "Running [PID "$(cat ${PID_FILE})"]" >&2
exit
else
# If the process is not running, yet there is a PID file--like in the case
# of a crash or sudden reboot--then get rid of the ${LOCK_DIR}
rm -rf ${LOCK_DIR}
exit
fi
fi
L'idée est ce noyau général, où j'ai echo "Hello world!"
- est là où se trouve le cœur de votre script. Le reste est essentiellement un mécanisme/logique de verrouillage basé sur mkdir
. Une bonne explication du concept se trouve dans cette réponse :
mkdir crée un répertoire s'il n'existe pas encore, et si c'est le cas, il définit un code de sortie. Plus important encore, il fait tout cela en une seule action atomique, ce qui le rend parfait pour ce scénario.
Donc, dans le cas de votre rsync
processus, je recommanderais d'utiliser ce script en changeant simplement le echo
commande à votre rsync
commande. Changez également le LOCK_NAME
à quelque chose comme RSYNC_PROCESS
et alors vous êtes prêt à partir.
Maintenant avec votre rsync
enveloppé dans ce script, vous pouvez configurer la tâche cron pour qu'elle s'exécute toutes les minutes sans aucun risque de condition de course où deux ou plusieurs rsync
les processus se battent pour faire la même chose. Cela vous permettra d'augmenter la vitesse ou rsync
mises à jour qui n'élimineront pas le problème des fichiers partiels en cours de transfert, mais cela aidera à accélérer le processus global afin que le fichier complet puisse être correctement copié à un moment donné.
Oui - et le fichier peut être corrompu si rsync lit le fichier en même temps que le fichier est en cours d'écriture.
Vous pouvez essayer ceci :https://unix.stackexchange.com/a/2558
Vous pouvez également le scripter avec lsof :
lsof /path/to file
Un code de sortie de 0 signifie que le fichier est en cours d'utilisation, et un code de sortie de 1 signifie qu'il n'y a aucune activité sur ce fichier.