Verhalten von rsync mit Datei, die noch geschrieben wird?

12

Wenn Apache gerade eine große Datei schreibt und ein rsync-Cron-Job für diese Datei ausgeführt wird, versucht rsync, die Datei zu kopieren?

Beispiel

  • Apache-1: Hat eine große Datei, in die geschrieben wird /var/www.
  • Apache-2: Klon von Apache-1. Alle fünf Minuten hat cron rsync ausgeführt, um /var/wwwsynchronisiert zu werden.
Louis
quelle

Antworten:

20

Wenn Apache eine Datei an einen Ort schreibt und das Schreiben noch nicht abgeschlossen hat und dannrsync einschaltet, rsyncwird alles kopiert, was sich dort befindet.

Das heißt, wenn Apache mit einer 5-MB-Datei arbeitet, werden nur 2 MB geschrieben und rsyncdie Teil-2-MB-Datei wird kopiert. Diese Datei scheint also auf dem Zielserver "beschädigt" zu sein.

Abhängig von der Größe der von Ihnen verwendeten Dateien können Sie die --inplaceOption in verwenden rsync, um Folgendes zu 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 nach Abschluss an ihren Platz zu verschieben, schreibt rsync stattdessen die aktualisierten Daten direkt in das Ziel Datei.

Dies hat den Vorteil, dass bei einer 5-MB-Datei, bei der beim ersten Durchlauf nur 2 MB kopiert wurden, der nächste Lauf bei 2 MB aufgenommen wird und die Datei weiter kopiert wird, bis die vollständigen 5 MB vorhanden sind.

Das Negative ist, dass es zu einer Situation kommen kann, in der jemand auf den Webserver zugreift, während eine Datei kopiert wird, und dann eine Teildatei sieht. Meiner Meinung nach rsyncfunktioniert es am besten, wenn eine „unsichtbare“ Datei standardmäßig zwischengespeichert und dann sofort verschoben wird. Dies --inplaceist jedoch gut für Szenarien geeignet, in denen große Dateien und Bandbreitenbeschränkungen einer großen Datei im Wege stehen, die leicht von der ersten Seite kopiert werden kann.

Das heißt, Sie sagen dies; Der Schwerpunkt liegt bei mir:

Alle fünf Minuten hat cron rsync ausgeführt…

Ich gehe also davon aus, dass Sie ein Bash-Skript eingerichtet haben, um diesen Cron-Job zu verwalten. Nun, die Sache ist rsyncklug 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, versuchen Sie anscheinend, nicht rsyncaufeinander zu treten, wenn es schneller geht. Das heißt, wenn Sie es jede Minute ausführen, besteht das Risiko, dass einer oder mehrere der rsyncProzesse aufgrund der Dateigröße oder der Netzwerkgeschwindigkeit noch ausgeführt werden und der nächste Prozess nur im Wettbewerb damit steht. eine Rennbedingung.

Eine Möglichkeit, dies zu vermeiden, besteht darin, Ihren gesamten rsyncBefehl in ein Bash-Skript zu packen, das nach einer Dateisperre sucht. Unten ist ein Boilerplate-Bash-Skript-Framework, das ich für solche Fälle verwende.

Beachten Sie, dass einige Leute die Verwendung empfehlen, flockaber da flockes auf einigen von mir verwendeten Systemen nicht installiert ist - und ich viel zwischen Ubuntu (das es hat) und Mac OS X (das es nicht hat) springe - verwende ich 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, dass der allgemeine Kern - wo ich ihn habe echo "Hello world!"- das Herz Ihres Skripts ist. Der Rest ist im Grunde ein Sperrmechanismus / eine Sperrlogik, die auf basiert mkdir. Eine gute Erklärung des Konzepts finden Sie in dieser Antwort :

mkdir erstellt ein Verzeichnis, falls es noch nicht vorhanden ist, und legt in diesem Fall einen Exit-Code fest. Noch wichtiger ist, dass dies alles in einer einzigen atomaren Aktion erledigt wird, was es perfekt für dieses Szenario macht.

Im Falle Ihres rsyncProzesses würde ich empfehlen, dieses Skript zu verwenden, indem Sie einfach den echoBefehl in Ihren rsyncBefehl ändern . Ändern Sie auch das LOCK_NAMEin etwas wie RSYNC_PROCESSund dann können Sie loslegen.

Jetzt, da Sie rsyncin dieses Skript rsynceingebunden sind , können Sie festlegen, dass der Cron-Job jede Minute ausgeführt wird, ohne dass das Risiko einer Rennbedingung besteht, bei der zwei oder mehr Prozesse darum kämpfen, dasselbe zu tun. Auf diese Weise können Sie die Geschwindigkeit oder rsyncAktualisierungen erhöhen, wodurch das Problem der Übertragung von Teildateien nicht beseitigt wird. Dies beschleunigt jedoch den Gesamtprozess, sodass die vollständige Datei zu einem bestimmten Zeitpunkt ordnungsgemäß kopiert werden kann.

JakeGould
quelle
1
Vielen Dank für den Hinweis auf die Möglichkeit, dass mehrere Rsyncs ausgeführt werden. Daran habe ich nicht gedacht. Das Skript klingt großartig. Ich habe nur versucht, die Probleme beim Synchronisieren einer Site mit Lastenausgleich mit rsync zu verstehen, und dies scheint sie zu lindern. Wunderbarer Bonus. Ich habe immer noch das Gefühl, dass dies vielleicht der falsche Ansatz ist ... aber mal sehen :)
Louis
@ Louis Gern geschehen! Wenn Sie Ordner basierend auf sofortigen Dateiänderungen synchron halten möchten, würde ich dringend empfehlen, die Verwendung / Anpassung zu prüfen lsyncd. Es ermöglicht Ihnen, "Hot Folders" zu haben, die wirklich auf Aktivitäten in ihnen achten und dann auf diese Dateien reagieren, wenn Änderungen vorgenommen werden. Ich verwende rsyncviel, wie in meiner Antwort beschrieben, aber ich verwende es lsyncdfür Fälle, die eine nicht-cron / unmittelbarere Form der Aktion erfordern.
JakeGould
3

Ja - und die Datei ist möglicherweise beschädigt, wenn rsync die Datei gleichzeitig mit dem Schreiben der Datei liest.

Sie können dies versuchen: /unix//a/2558

Sie können es auch mit lsof schreiben:

lsof /path/to file

Ein Exit-Code von 0 bedeutet, dass die Datei verwendet wird, und ein Exit-Code von 1 bedeutet, dass für diese Datei keine Aktivität vorhanden ist.

Rebelshrug
quelle