Wenn Apache eine Datei irgendeiner Art an einen Ort schreibt und das Schreiben noch nicht abgeschlossen hat und dann rsync
Tritt ein, rsync
wird kopieren, was dort sitzt.
Das heißt, wenn Apache mit einer 5-MB-Datei arbeitet, werden nur 2 MB geschrieben und rsync
einsetzt, wird die teilweise 2 MB große Datei kopiert. Diese Datei scheint also auf dem Zielserver „beschädigt“ zu sein.
Abhängig von der Größe der verwendeten Dateien können Sie den --inplace
verwenden Option in rsync
Folgendes tun:
Diese Option ändert, wie rsync eine Datei überträgt, wenn die Daten der Datei aktualisiert werden müssen:Anstelle der Standardmethode, eine neue Kopie der Datei zu erstellen und sie an ihren Platz zu verschieben, wenn sie fertig ist, schreibt rsync stattdessen die aktualisierten Daten direkt in die Zieldatei.
Dies hat den Vorteil, dass, wenn bei einer 5-MB-Datei beim ersten Durchlauf nur 2 MB kopiert wurden, der nächste Durchlauf bei 2 MB beginnt und die Datei weiter kopiert wird, bis die vollen 5 MB vorhanden sind.
Das Negative ist, dass es eine Situation schaffen könnte, in der jemand auf den Webserver zugreift, während eine Datei kopiert wird, und dann würde er eine Teildatei sehen. Meiner Meinung nach rsync
funktioniert am besten in seinem Standardverhalten, eine „unsichtbare“ Datei zwischenzuspeichern und sie dann sofort an ihren Platz zu verschieben. Aber --inplace
eignet sich gut für Szenarien, in denen große Dateien und Bandbreitenbeschränkungen dem einfachen Kopieren einer großen Datei von Anfang an im Wege stehen könnten.
Das heißt, Sie geben dies an; Hervorhebung von mir:
Alle fünf Minuten hat cron rsync ausgeführt…
Ich nehme also an, Sie haben ein Bash-Skript, um diesen Cron-Job zu verwalten? Nun, das Ding ist rsync
ist intelligent genug, um nur die Dateien zu kopieren, die kopiert werden müssen. Und wenn Sie ein Skript haben, das alle 5 Minuten ausgeführt wird, scheinen Sie zu vermeiden, rsync
zu haben aufeinander treten, wenn es schneller geht. Das heißt, wenn Sie es jede Minute laufen lassen, besteht die Gefahr, dass einer oder mehrere der rsync
Prozesse würden aufgrund der Dateigröße oder Netzwerkgeschwindigkeit noch laufen und der nächste Prozess würde nur damit konkurrieren; eine Rennbedingung.
Eine Möglichkeit, dies zu vermeiden, besteht darin, Ihr gesamtes rsync
zu umschließen Befehl in einem Bash-Skript, das nach einer Dateisperre sucht; Unten ist ein Bash-Script-Framework mit Boilerplate, das ich für solche Fälle verwende.
Beachten Sie, dass einige Leute die Verwendung von flock
empfehlen werden aber seit flock
auf einigen Systemen, die ich verwende, nicht installiert ist – und ich wechsle häufig zwischen Ubuntu (das es hat) und Mac OS X (das es nicht hat) – ich verwende dieses einfache Framework ohne wirkliche Probleme:
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
Die Idee ist dieser allgemeine Kern – wo ich echo "Hello world!"
habe – ist das Herzstück Ihres Skripts. Der Rest ist im Grunde ein Sperrmechanismus/eine Logik basierend auf mkdir
. Eine gute Erklärung des Konzepts finden Sie in dieser Antwort:
mkdir erstellt ein Verzeichnis, falls es noch nicht existiert, und falls doch, setzt es einen Exit-Code. Noch wichtiger ist, dass es all dies in einer einzigen atomaren Aktion erledigt, was es perfekt für dieses Szenario macht.
Also im Fall Ihres rsync
Prozess, würde ich empfehlen, dieses Skript zu verwenden, indem Sie einfach den echo
ändern Befehl an Ihren rsync
Befehl. Ändern Sie auch LOCK_NAME
zu etwas wie RSYNC_PROCESS
und dann kann es losgehen.
Jetzt mit Ihrem rsync
In dieses Skript eingeschlossen, können Sie den Cron-Job so einstellen, dass er jede Minute ausgeführt wird, ohne dass das Risiko einer Rennbedingung besteht, bei der zwei oder mehr rsync
Prozesse kämpfen darum, dasselbe zu tun. Dadurch können Sie die Geschwindigkeit erhöhen oder rsync
Aktualisierungen, die das Problem der teilweisen Übertragung von Dateien nicht beseitigen, aber den Gesamtprozess beschleunigen helfen, sodass irgendwann die vollständige Datei ordnungsgemäß kopiert werden kann.
Ja - und die Datei könnte beschädigt werden, wenn rsync die Datei liest, während gleichzeitig in die Datei geschrieben wird.
Sie können dies versuchen:https://unix.stackexchange.com/a/2558
Sie können es auch mit lsof:
skriptenlsof /path/to file
Ein Exit-Code von 0 bedeutet, dass die Datei verwendet wird, und ein Exit-Code von 1 bedeutet, dass diese Datei nicht aktiv ist.