Jeśli Apache pisze jakiś plik w jednym miejscu i nie ukończył go zapisywać, a następnie rsync
uruchamia, rsync
skopiuje wszystko, co tam siedzi.
Oznacza to, że jeśli Apache ma do czynienia z plikiem 5 MB, zostanie zapisany tylko 2 MB i zostanie rsync
uruchomiony, częściowy plik 2 MB zostanie skopiowany. Wygląda więc na to, że plik jest „uszkodzony” na serwerze docelowym.
W zależności od rozmiaru używanych plików możesz użyć --inplace
opcji w, rsync
aby wykonać następujące czynności:
Ta opcja zmienia sposób, w jaki rsync przesyła plik, gdy dane pliku wymagają aktualizacji: zamiast domyślnej metody tworzenia nowej kopii pliku i przenoszenia go na miejsce po zakończeniu, rsync zapisuje zaktualizowane dane bezpośrednio do miejsca docelowego plik.
Zaletą tego jest to, że jeśli plik 5 MB ma tylko 2 MB skopiowane przy pierwszym uruchomieniu, następne uruchomienie pobierze 2 MB i będzie kontynuować kopiowanie pliku, aż pełne 5 MB będzie na swoim miejscu.
Negatywne jest to, że może stworzyć sytuację, w której ktoś uzyskuje dostęp do serwera WWW podczas kopiowania pliku, a następnie zobaczy plik częściowy. Moim zdaniem rsync
najlepiej sprawdza się w domyślnym zachowaniu buforowania „niewidzialnego” pliku, a następnie natychmiastowego przeniesienia go na miejsce. Ale --inplace
jest dobry w scenariuszach, w których duże pliki i ograniczenia przepustowości mogą przeszkadzać w łatwym kopiowaniu dużego pliku z pierwszego.
Powiedziałeś, że to stwierdzasz; nacisk jest mój:
Co pięć minut cron uruchamia rsync…
Więc zakładam, że masz jakiś skrypt bash do zarządzania tym zadaniem cron? Cóż, sprawa jest rsync
wystarczająco inteligentna, aby skopiować tylko pliki, które należy skopiować. A jeśli masz skrypt, który jest uruchamiany co 5 minut, wydaje się, że starasz się unikać rsync
na siebie nawzajem, jeśli idzie szybciej. Oznacza to, że jeśli uruchamiasz go co minutę, istnieje ryzyko, że jeden lub więcej rsync
procesów będzie nadal działać z powodu rozmiaru pliku lub szybkości sieci, a następny proces będzie po prostu z nim konkurował; warunki wyścigowe.
Jednym ze sposobów uniknięcia tego jest zawinięcie całego rsync
polecenia w skrypt bash, który sprawdza blokadę pliku; poniżej znajduje się szkielet skryptu bash, którego używam do takich przypadków.
Zauważ, że niektórzy ludzie zalecą używanie, flock
ale ponieważ flock
nie jest zainstalowany na niektórych systemach, których używam - i często przeskakuję między Ubuntu (który ma) i Mac OS X (który nie ma) - używam tej prostej struktury bez żadnego poważnego problemu:
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
Chodzi o to, że ten rdzeń - tam, gdzie ja mam echo "Hello world!"
- jest sercem twojego skryptu. Reszta jest w zasadzie mechanizmem blokującym / logiką opartą na mkdir
. Dobre wyjaśnienie tego pojęcia znajduje się w tej odpowiedzi :
mkdir tworzy katalog, jeśli jeszcze nie istnieje, a jeśli tak, ustawia kod wyjścia. Co ważniejsze, robi to wszystko w jednej akcji atomowej, dzięki czemu idealnie nadaje się do tego scenariusza.
Tak więc w przypadku twojego rsync
procesu poleciłbym użycie tego skryptu, po prostu zmieniając echo
polecenie na twoje rsync
. Zmień też LOCK_NAME
na coś takiego, RSYNC_PROCESS
a wtedy możesz zacząć.
Teraz, gdy Twój rsync
skrypt jest zawinięty, możesz ustawić zadanie crona do uruchamiania co minutę bez ryzyka warunków wyścigowych, w których dwa lub więcej rsync
procesów walczy o to samo. Umożliwi to zwiększenie prędkości lub rsync
aktualizacji, co nie wyeliminuje problemu przesyłania częściowych plików, ale pomoże przyspieszyć cały proces, aby w pewnym momencie można było poprawnie skopiować cały plik.