warum rsync keine Delta-Übertragung durchführt

7

Ich habe eine Binärdatei mit ca. 77 MB:

nupic@nupic-virtualbox:~/VboxSharedFolder/experiments/sync/exp2$ ls -lah src/
total 77M
drwxrwx--- 1 root vboxsf    0 Jun 21 13:31 .
drwxrwx--- 1 root vboxsf 4.0K Jun 21 16:21 ..
-rwxrwx--- 1 root vboxsf  77M May 27  2014 binary.bin

Ich habe mit gespielt rsyncund es ist eine Delta-Algorithmus-Funktion, um zu sehen, wie es funktioniert. Die Idee war, kleine Unterschiede in der Binärdatei zu machen und zu sehen, wie viele Daten mit verschiedenen Methoden übertragen wurden. Für diese Zwecke habe ich ein sehr einfaches Skript erstellt:

#!/bin/bash
# rsync does not trnansfers delta over local by default
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_local_default.log rsync -avcz --progress src/ dst/

# rsync -no-W should enables delta tranfer no matter if local or remote
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_local_delta_enabled.log rsync --no-W -avcz --progress src/ dst/

# rsync trnansfers delta over network by default
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_rsync_remote.log rsync -avcz -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --progress src/ nupic@localhost:/home/nupic/VboxSharedFolder/experiments/sync/exp2/dst/

# scp should transfers whole file not delta
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_scp.log scp src/binary.bin nupic@localhost:/home/nupic/VboxSharedFolder/experiments/sync/exp2/dst/

# cp always transfers whole file not delta
sed 's%\x00\x00\x00\x20\x66\x74\x79\x70\x69\x73\x6f\x6d\x00\x00\x02\x00%\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11%' src/binary.bin > dst/binary.bin
strace -f -e trace=read,write -o rw_cp.log cp src/binary.bin dst/binary.bin

Dann habe ich folgende Schleife zur Auswertung der Ergebnisse:

for i in *.log; do
  echo $i; cat $i | grep write | awk 'BEGIN {FS="="}{ sum += $2} END {print sum/1024/1024 "MB"}';
  echo "###########";
done

Hier sind die Ergebnisse:

rw_cp.log
67.8075MB
###########
rw_rsync_local_default.log
146.697MB
###########
rw_rsync_local_delta_enabled.log
66.8765MB
###########
rw_rsync_remote.log
0.0707941MB
###########
rw_scp.log
136.048MB
###########

Von diesen fünf Experimenten sind mir nur zwei klar:

  1. cpschreibt ungefähr die gleiche Anzahl von Bytes wie die Größe der Originaldatei ( rw_cp.log).
  2. rsyncVerwendet den Delta-Algorithmus, wenn das Ziel entfernt ist (über das Netzwerk) ( rw_rsync_remote.log)

Und hier sind mir unklare Dinge:

  1. Warum beim Aufrufen rsyncvon beiden srcund dstbeim localhostSchreiben werden ungefähr zwei Bytes so groß wie die Originaldatei geschrieben? ( rw_rsync_local_default.log)
  2. Warum überträgt die --no-WOption für rsyncnicht nur Delta für srcund dstweiter, localhostwie hier angegeben , und warum überträgt sie immer noch ungefähr die gesamte Datei? ( rw_rsync_local_delta_enabled.log)
  3. Bonus: Warum werden scpungefähr doppelt Bytes als ursprüngliche Dateigröße übertragen? Ich verstehe, dass es eine Verschlüsselung gibt, aber zweimal scheint mir groß ( rw_scp.log).
Wakan Tanka
quelle

Antworten:

4

Kurz gesagt, die Hauptfrage zu beantworten, rsyncscheint die doppelte Anzahl von Bytes zu schreiben, da zwei Prozesse / Threads zum Kopieren erzeugt werden und zwischen den Prozessen ein Stream-Daten und zwischen dem empfangenden Prozess ein anderer Datenstrom in die Zieldatei vorhanden sind.

Wir können dies erkennen, indem wir uns die straceAusgabe genauer ansehen, die Prozess-IDs am Anfang der Datei und auch die Dateideskriptornummern in den writeAufrufen können verwendet werden, um verschiedene Schreib- "Streams" voneinander zu unterscheiden.

Vermutlich ist dies so, dass eine lokale Übertragung genau wie eine Remoteübertragung funktionieren kann, nur die Quelle und das Ziel befinden sich auf demselben System.


Wenn Sie so etwas wie verwenden strace -e trace=process,socketpair,open,read,write, werden einige Threads angezeigt, die erzeugt wurden, wobei das Socket-Paar zwischen ihnen erstellt wurde, und verschiedene Threads, die die Eingabe- und Ausgabedateien öffnen.

Ein Testlauf ähnlich Ihrem:

$ rm test2
$ strace -f -e trace=process,socketpair,open,close,dup,dup2,read,write -o rsync.log rsync -avcz --progress test1 test2
$ ls -l test1 test2
-rw-r--r-- 1 itvirta itvirta 81920004 Jun 21 20:20 test1
-rw-r--r-- 1 itvirta itvirta 81920004 Jun 21 20:20 test2

Nehmen wir eine Anzahl von Bytes, die für jeden Thread separat geschrieben wurden:

$ for x in 15007 15008 15009  ; do echo -en "$x: " ; grep -E "$x (<... )?write"  rsync.log | awk 'BEGIN {FS=" = "} {sum += $2} END {print sum}'  ; done 
15007: 81967265
15008: 49
15009: 81920056

Was ziemlich genau mit der obigen Theorie übereinstimmt. Ich habe nicht überprüft, welche anderen 40 KB vom ersten Thread geschrieben wurden, aber ich gehe davon aus, dass die Fortschrittsausgabe gedruckt wird und alle Metadaten über die synchronisierte Datei rsync auf das andere Ende übertragen werden müssen.


Ich habe es nicht überprüft, aber ich schlage vor, dass selbst bei aktivierter Delta-Komprimierung das "entfernte" Ende von rsync die Datei möglicherweise (größtenteils) vollständig ausschreibt, was zu ungefähr der gleichen Anzahl von Schreibvorgängen wie bei cp führt. Die Übertragung zwischen den rsync-Threads ist kleiner, aber die endgültige Ausgabe ist immer noch dieselbe.

ilkkachu
quelle
1
In ähnlicher Weise scpwird ein untergeordneter sshProzess erstellt, um das eigentliche SSH-Protokoll (Handshake, Verschlüsselung und MAC) auszuführen. Auf diese Weise liest der Elternteil die Datei und schreibt über die Pipe in das Kind und schreibt auch die Fortschrittsanzeige in das Terminal, das ziemlich klein ist. Das Kind liest die Pipe und liest und schreibt den Socket für das SSH-Protokoll, wodurch normalerweise 1-2 KB Start und möglicherweise 1% zu den Daten hinzugefügt werden.
Dave_thompson_085
@ilkkachu Ich habe versucht, geschriebene Bytes pro Kind zu bekommen, aber vielleicht stimmt etwas mit Regexp nicht. Versuchter Code:for x in $(awk '{print $1}' rsync.log | sort | uniq); do; echo -en "$x: "; grep -E "$x (<... )?write" rsync.log | awk 'BEGIN {FS=" = "} {sum += $2} END {print sum}'; done
Wakan Tanka
2

Standardmäßig erstellt rsync zuerst eine neue Kopie der Zieldatei und ersetzt sie dann aus verschiedenen Sicherheitsgründen. Sie können dies überschreiben, indem Sie --inplacezusammen mit angeben --no-whole-file. Dadurch wird rsync angewiesen, die Zieldatei direkt zu bearbeiten und dabei die verschiedenen (in dieser Situation normalerweise geringfügigen) Risiken zu akzeptieren, die in der Manpage dokumentiert sind.

kartik_subbarao
quelle