Warum läuft die Weiterleitung von "dd" durch gzip so viel schneller als eine direkte Kopie?

79

Ich wollte einen Pfad von einem Computer in meinem Netzwerk zu einem anderen Computer im selben Netzwerk über eine 100-Mbit / s-Leitung sichern. Dafür habe ich getan

dd if=/local/path of=/remote/path/in/local/network/backup.img

Das gab mir eine sehr niedrige Netzwerkübertragungsgeschwindigkeit von etwa 50 bis 100 kB / s, die für immer gedauert hätte. Also habe ich es gestoppt und beschlossen, es spontan zu zippen, um es viel kleiner zu machen, damit der zu übertragende Betrag geringer ist. So tat ich

dd if=/local/path | gzip > /remote/path/in/local/network/backup.img.gz

Aber jetzt bekomme ich so etwas wie 1 MB / s Netzwerkübertragungsgeschwindigkeit, also einen Faktor von 10 bis 20 schneller. Nachdem ich das bemerkt hatte, testete ich es auf mehreren Pfaden und Dateien, und es war immer dasselbe.

Warum Rohrleitungen dddurch gzipauch um einen großen Faktor die Übertragungsraten zu erhöhen , anstatt nur die ByteLength des Stroms um einen großen Faktor zu reduzieren? Ich hatte stattdessen aufgrund des höheren CPU-Verbrauchs beim Komprimieren sogar einen kleinen Rückgang der Übertragungsraten erwartet, aber jetzt bekomme ich ein doppeltes Plus. Nicht, dass ich nicht glücklich wäre, aber ich wundere mich nur. ;)

Foo Bar
quelle
1
512 Bytes war die Standardblockgröße für die Dateispeicherung in frühen Unix-Versionen. Da in Unix / Linux alles eine Datei ist, wurde sie zur Standardeinstellung für nahezu alles. Neuere Versionen der meisten Dienstprogramme haben das erhöht, aber nicht dd.
DocSalvager
Die einfache Antwort ist, dass ddmit 1 MB / s ... direkt in die Warteleitung gzipausgegeben wird. Es hat sehr wenig mit der Blockgröße zu tun.
Tullo_x86

Antworten:

100

ddStandardmäßig wird eine sehr kleine Blockgröße verwendet - 512 Bytes (!!). Das heißt, viele kleine Lese- und Schreibvorgänge. ddIn Ihrem ersten Beispiel wurde scheinbar eine große Anzahl von Netzwerkpaketen mit einer sehr kleinen Nutzlast generiert, wodurch der Durchsatz verringert wurde.

Auf der anderen Seite gzipist es intelligent genug, um E / A-Vorgänge mit größeren Puffern durchzuführen. Das heißt, eine kleinere Anzahl großer Schreibvorgänge über das Netzwerk.

Können Sie es ddmit einem größeren bs=Parameter noch einmal versuchen und sehen, ob es diesmal besser funktioniert?


quelle
20
Danke, probiert direktes Kopieren ohne gzip und eine Blockgröße von bs=10M-> schnelle Netzwerkübertragung von etwas über 3 oder 4 MB / s. Eine höhere Blockgröße gzipänderte nichts im Vergleich zu einer kleinen Blockgröße gzip.
Foo Bar
7
Wenn Sie sehen möchten, welche hohen Blockgrößen vorhanden sind, versuchen Sie es mit einer anderen dd nach dem gzip.
Joshua
Macht gzip seine eigene Ausgabepufferung oder benutzt es nur stdio?
Barmar
@Barmar Wenn ich die Quelle richtig lese, wird sie einfach write(3)in den Puffer geschrieben.
@CongMa Sie können auch versuchen, pigz anstelle von gzip zu verwenden, es wird noch schneller
funktionieren
4

Etwas spät dazu, aber könnte ich hinzufügen ...

In einem Interview wurde ich einmal gefragt, welche Methode zum Klonen von Bit-für-Bit-Daten am schnellsten möglich und mit ddoder dc3dd( DoD-finanziert ) grob beantwortet wäre . Der Interviewer bestätigte, dass die Weiterleitung ddzu ddeffizienter ist, da dies lediglich das gleichzeitige Lesen / Schreiben oder programmiertechnisch stdin/stdoutzulässt, wodurch sich die Schreibgeschwindigkeit letztendlich verdoppelt und die Übertragungszeit halbiert.

dc3dd verb=on if=/media/backup.img | dc3dd of=/dev/sdb
Sadik Tekin
quelle
1
Ich glaube nicht, dass das stimmt. Ich habe es gerade versucht. dd status=progress if=/dev/zero count=100000 bs=1M of=/dev/nullbetrug 22,5 GB / s, dd status=progress if=/dev/zero count=100000 bs=1M | dd of=/dev/null bs=1Mwar 2,7 GB. Die Pfeife macht es also langsamer.
falsePockets
0

Cong ist richtig. Sie streamen die Blöcke von der unkomprimierten Festplatte auf einen Remote-Host. Ihre Netzwerkschnittstelle, Ihr Netzwerk und Ihr Remote-Server sind die Einschränkung. Zuerst müssen Sie die Leistung von DD steigern. Wenn Sie einen bs = -Parameter angeben, der am Plattenpufferspeicher ausgerichtet ist, wird die beste Leistung von der Platte erzielt. Sagen Sie zum Beispiel bs = 32M. Dadurch wird der gzip-Puffer mit der SATA- oder SAS-Zeilenrate aus dem Laufwerkspuffer gefüllt. Die Festplatte ist eher für sequenzielle Übertragungen geeignet, um einen besseren Durchsatz zu erzielen. Gzip komprimiert die Daten im Stream und sendet sie an Ihren Standort. Wenn Sie NFS verwenden, kann die NFS-Übertragung minimal sein. Wenn Sie SSH verwenden, übernehmen Sie den SSH-Kapselungs- und Verschlüsselungsaufwand. Wenn Sie Netcat verwenden, haben Sie keine zusätzliche Verschlüsselung.

Robert
quelle
0

Ich gehe davon aus, dass die "Übertragungsgeschwindigkeit", auf die Sie sich beziehen, von gemeldet wird dd. Dies ist tatsächlich sinnvoll, da ddtatsächlich das 10-fache der Datenmenge pro Sekunde übertragen wird ! Die ddÜbertragung erfolgt jedoch nicht über das Netzwerk. Dieser Auftrag wird vom gzipProzess verarbeitet.

Ein Kontext: gzipVerwendet Daten aus der Eingabe-Pipe so schnell wie möglich, um den internen Puffer zu leeren. Die Geschwindigkeit, mit der gzipder Puffer geleert wird, hängt von einigen Faktoren ab:

  • Die E / A-Schreibbandbreite (die durch das Netzwerk eingeschränkt ist und konstant geblieben ist)
  • Die E / A-Lesebandbreite (die weit über 1 MB / s liegen wird, wenn auf einem modernen Computer von einer lokalen Festplatte gelesen wird) ist daher kein wahrscheinlicher Engpass.
  • Die Komprimierungsrate (von der ich annehme, dass Ihre 10-fache Geschwindigkeit bei etwa 10% liegt, was darauf hinweist, dass Sie eine Art sich stark wiederholenden Text wie eine Protokolldatei oder eine XML-Datei komprimieren)

In diesem Fall kann das Netzwerk also 100 kB / s verarbeiten und gzipkomprimiert die Daten um 10: 1 (und wird von der CPU nicht beeinträchtigt ). Dies bedeutet, dass bei einer Ausgabe von 100 kB / s 1 MB / s verbraucht werdengzip können und die Verbrauchsrate angezeigt wird .dd

Tullo_x86
quelle