Langsameres Kopieren von Datenträgern / Datenträgern

28

Gibt es eine Methode, um den Kopiervorgang unter Linux zu verlangsamen?

Ich habe eine große Datei, sagen wir 10 GB, und ich möchte sie in ein anderes Verzeichnis kopieren, aber ich möchte sie nicht mit voller Geschwindigkeit kopieren. Nehmen wir an, ich möchte es mit einer Geschwindigkeit von 1 MB / s kopieren, nicht schneller. Ich möchte einen Standard-Linux- cpBefehl verwenden.

Ist das möglich? (Wenn ja, wie?)

Bearbeiten : Also werde ich mehr Kontext zu dem hinzufügen, was ich erreichen will.

Ich habe ein Problem mit dem ArchLinux-System beim Kopieren großer Dateien über USB (auf ein USB-Laufwerk, eine USB-Festplatte usw.). Nach dem Auffüllen des USB-Pufferspeichers reagiert mein System nicht mehr (selbst die Maus bleibt stehen; sie bewegt sich nur sporadisch). Der Kopiervorgang ist noch nicht abgeschlossen, beansprucht jedoch 100% der Box. Wenn der Kopiervorgang abgeschlossen ist, kehrt alles zum Normalzustand zurück - alles reagiert wieder perfekt.

Vielleicht ist es ein Hardwarefehler, ich weiß es nicht, aber ich weiß, ich habe zwei Computer mit diesem Problem (beide sind unter ArchLinux, einer ist eine Desktop-Box, der zweite ist ein Laptop).

Die einfachste und schnellste "Lösung" für dieses Problem (ich stimme zu, es ist nicht die "echte" Lösung, sondern nur ein hässlicher "Hack") besteht darin, zu verhindern, dass dieser Puffer voll wird, indem die Datei mit einer durchschnittlichen Schreibgeschwindigkeit des USB - Laufwerks kopiert wird, z mir wäre das genug

antonone
quelle
7
Wenn Sie die Kopiergeschwindigkeit von Festplatte zu Festplatte begrenzen möchten, um für andere E / A-gebundene Prozesse im System "nett" zu sein, ist es wahrscheinlich besser, die Möglichkeit des Kernels zu nutzen, die E / A-Zeitplanung zu optimieren stattdessen. Insbesondere ionicekann verwendet werden , um sicherzustellen , dass Ihr Disk-to-Disk - Kopiervorgang geplant ist I / O mit einer niedrigeren Priorität als normale Prozesse.
Steven Montag
3
Dies ist eine klassische XY-Problemfrage . Sie sollten sich stattdessen fragen, warum Ihr Desktop nicht mehr reagiert, wenn Sie Dateien auf ein USB-Gerät kopieren.
Michael Hampton
4
Linux hat heutzutage tatsächlich lächerlich große I / O-Puffer. RAM-Größen sind schneller gewachsen als Massenspeichergeschwindigkeiten. Vielleicht könnten Sie die Kopie mit dd (1) ausführen und synchronisieren, damit sie tatsächlich regelmäßig synchronisiert wird, anstatt gepuffert zu werden? Der Pipe Viewer (pv) verfügt über eine Geschwindigkeitsbegrenzungsoption. So etwas wie cat file | pv -L 3k > outfile. Beides ist jedoch nicht dasselbe wie die Verwendung von cp (1).
ptman
@MichaelHampton, es gibt mehrere ungelöste Themen zu diesem Thema im ArchLinux-Forum. Ich dachte mir, ich werde versuchen, damit anders umzugehen, nur damit es funktioniert.
Antonone
@antonone Aber Unix.SE ist kein ArchLinux-Forum. Jemand hier könnte eine Lösung haben.
Izkata

Antworten:

23

Sie können eine Pipe mit pv -qL(oder einer cstream -tähnlichen Funktion) drosseln.

tar -cf - . | pv -q -L 8192 | tar -C /your/usb -xvf -

-q Entfernt stderr Fortschrittsberichte.

Das -LLimit ist in Bytes.

Mehr über die --rate-limit/-LFlagge von der man pv:

-L RATE, --rate-limit RATE

    Limit the transfer to a maximum of RATE bytes per second.
    A suffix of "k", "m", "g", or "t" can be added to denote
    kilobytes (*1024), megabytes, and so on.

Diese Antwort wies ursprünglich darauf hin, throttleaber dieses Projekt ist nicht mehr verfügbar und ist aus einigen Paketsystemen herausgerutscht.

Matt
quelle
Wenn cpdies nicht verlangsamt werden kann, ist die Verwendung eines benutzerdefinierten Befehls die einzige Option, die ich denke.
Antonone
1
Klingt im Vergleich zumrsync
LinuxSecurityFreak 15.12.16
sieht komplizierter aus, ist aber für mich brauchbarer. Sie müssen einen Dateisperrmechanismus testen und das Kopieren auf einige Bytes / s verlangsamen, was mit rsync nicht möglich zu sein scheint.
Ich
Leider
cljk
1
@cljk aktualisiert auf pv. Vielen Dank.
Matt
23

Stattdessen cp -a /foo /barkönnen Sie rsyncdie Bandbreite auch nach Bedarf nutzen und begrenzen.

Aus dem rsyncHandbuch:

--bwlimit=KBPS

I / O-Bandbreite begrenzen; KB pro Sekunde

Der aktuelle Befehl, der auch den Fortschritt anzeigt, würde also so aussehen:

rsync -av --bwlimit=100 --progress /foo /bar
LinuxSecurityFreak
quelle
Das klingt nach einer guten Idee, alte Laufwerke zu kopieren, die ich nicht verprügeln möchte.
Jeremyjjbrown
Funktioniert nicht zum Lesen von /dev/zerooder/dev/random
cdosborn
rsync -a --bwlimit=1500 /source /destinationFunktioniert perfekt, um riesige Ordner mit einer Geschwindigkeit von 1,5 MB / s zu kopieren (was ein guter Kompromiss zwischen der Vermeidung von Server-Verlangsamungen und einem geringen Zeitaufwand ist)
Lucaferrario
Anmerkung: Auch wenn die Manpage besagt, dass Sie Buchstaben für Einheiten verwenden können, 20mwird sie beispielsweise nicht auf allen Plattformen unterstützt. Halten Sie sich daher besser an die KByte-Notation.
Hubert Grzeskowiak
hat meinen Tag gerettet! cgroup hat cgexec -g ... cp /in /outnicht die ganze Zeit gearbeitet (vom Terminal hat manchmal gearbeitet, vom Skript nie) und ich habe keine Ahnung warum ...
Aquarius Power
13

Ich würde annehmen, dass Sie versuchen, andere Aktivitäten nicht zu stören. Neuere Linux-Versionen enthalten Funktionen, mit ionicedenen Sie die Planung von E / A steuern können.

Neben dem Zulassen verschiedener Prioritäten gibt es eine zusätzliche Option, um die E / A auf Zeiten zu beschränken, in denen sich die Festplatte ansonsten im Leerlauf befindet. Der Befehl man ionicezeigt die Dokumentation an.

Versuchen Sie, die Datei mit einem Befehl wie dem folgenden zu kopieren:

ionice -c 3 cp largefile /new/directory

Wenn sich die beiden Verzeichnisse auf demselben Gerät befinden, können Sie feststellen, dass das Verknüpfen der Datei die gewünschten Aktionen ausführt. Wenn Sie zu Sicherungszwecken kopieren, verwenden Sie diese Option nicht. lnist extrem schnell, da die Datei selbst nicht kopiert wird. Versuchen:

ln largefile /new/directory

Oder wenn Sie nur von einem Verzeichnis auf einem anderen Gerät darauf zugreifen möchten, versuchen Sie Folgendes:

ln -s largefile /new/directory
BillThor
quelle
funktioniert ionice unter linux? Ich lese es einfach "emulieren" Arbeit und es gibt keinen wirklichen Unterschied? +1 für Links
Nick
1
@ Nick Wenn ich es benutzt habe, hat es sich wie erwartet verhalten. Der Prozess, auf den ich ionice angewendet habe, verlangsamte sich erheblich, und die anderen Prozesse, die I / O benötigten, konnten wie erwartet ausgeführt werden. Mit einer moderaten E / A-Last von anderen Prozessen konnte ich einen Prozess mit hoher E / A-Leistung effektiv unterbrechen, indem ich wie erwartet die maximale "Feinheit" anwandte. Sobald keine konkurrierenden E / A mehr vorhanden waren, verlief der ionisierte Prozess normal.
BillThor
mit der 400MB Datei habe ich von einer HD auf eine SSD kopiert, die ersten 10s hat es einwandfrei geklappt, dann sah ich plötzlich hohe IO Belastung und musste wie 1min Maschine einfrieren: /. Ich habe das gleiche Problem mit Cgroup Write Io Throttle, wo es manchmal funktioniert und andere es überhaupt nicht funktioniert.
Aquarius Power
7

Wenn die ioniceLösung nicht ausreicht (warum auch immer) und Sie I / O wirklich auf einen absoluten Wert beschränken möchten, gibt es mehrere Möglichkeiten:

  1. die wahrscheinlich einfachste: ssh. Es gibt ein eingebautes Bandbreitenlimit. Sie würden zB tar(anstelle von cp) oder scp(wenn das gut genug ist; ich weiß nicht, wie es mit Symlinks und Hardlinks umgeht) oder verwenden rsync. Diese Befehle können ihre Daten weiterleiten ssh. Wenn tarSie schreiben /dev/stdout(oder -), sshleiten Sie dies taran den Client weiter, der einen anderen auf der "entfernten" Seite ausführt .

  2. Elegant, aber nicht im Vanillekern (AFAIK): Das Device-Mapper-Ziel ioband. Dies funktioniert natürlich nur, wenn Sie entweder das Quell- oder das Ziel-Volume ummounten können.

  3. Selbstgeschriebener Spaß: grep "^write_bytes: " /proc/$PID/ioGibt die Datenmenge an, die ein Prozess geschrieben hat. Sie könnten ein Skript schreiben, das cpim Hintergrund startet , z. B. eine Zehntelsekunde ruht, den Hintergrundprozess stoppt cp( kill -STOP $PID), den geschriebenen Betrag prüft (und in diesem Fall ungefähr den gleichen Wert liest) und berechnet, wie lange er dauert cpmuss pausieren, um die durchschnittliche Übertragungsrate auf den beabsichtigten Wert zu senken, für diese Zeit schläft, aufwacht cp( kill -CONT $PID) und so weiter.

Hauke ​​Laging
quelle
Ja, normalerweise verwende ich nur LFTP, um eine Verbindung zu LocalHost über SCP herzustellen und die Bandbreite von dort zu begrenzen.
Antonone
5

Ihr Problem liegt wahrscheinlich nicht an Ihrem Computer, an sich ist es wahrscheinlich in Ordnung. Aber diese USB-Flash-Übergangsschicht hat einen eigenen Prozessor, der all Ihre Schreibvorgänge abbildet, um so viel wie einen zu 90% fehlerhaften Flash-Chip zu kompensieren, wer weiß? Sie überfluten es, dann überfluten Sie Ihre Puffer, dann überfluten Sie den gesamten Bus, dann stecken Sie fest, Mann - schließlich sind alle Ihre Sachen dort. Es klingt vielleicht kontraintuitiv, aber was Sie wirklich brauchen, ist die Blockierung von E / A - Sie müssen die FTL das Tempo bestimmen lassen und dann einfach mithalten.

(Zum Hacken von FTL-Mikrocontrollern: http://www.bunniestudios.com/blog/?p=3554 )

Alle obigen Antworten sollten funktionieren, also ist dies eher ein "Ich auch!" als alles andere: Ich war total da, Mann. Ich habe meine eigenen Probleme mit rsyncs --bwlimit arg gelöst (2,5 MB schienen der Sweet Spot für einen einzigen fehlerfreien Durchlauf zu sein - alles andere und ich würde mit Schreibschutzfehlern enden). rsync war für meinen Zweck besonders geeignet, da ich mit ganzen Dateisystemen arbeitete - es gab also viele Dateien - und einfach ein zweites Mal rsync ausführen konnte, um alle Probleme des ersten Laufs zu beheben (was notwendig war, wenn ich ungeduldig wurde und es versuchte) an 2.5mbs vorbeifahren).

Trotzdem denke ich, dass das für eine einzelne Datei nicht ganz so praktisch ist. In Ihrem Fall können Sie einfach per Pipe zu dd set auf raw-write setzen - Sie können jede Eingabe auf diese Weise verarbeiten, aber nur jeweils eine Zieldatei (obwohl diese einzelne Datei natürlich ein ganzes Blockgerät sein kann).

## OBTAIN OPTIMAL IO VALUE FOR TARGET HOST DEV ##
## IT'S IMPORTANT THAT YOUR "bs" VALUE IS A MULTIPLE ##
## OF YOUR TARGET DEV'S SECTOR SIZE (USUALLY 512b) ##
% bs=$(blockdev --getoptio /local/target/dev)

## START LISTENING; PIPE OUT ON INPUT ##
% nc -l -p $PORT | lz4 |\ 
## PIPE THROUGH DECOMPRESSOR TO DD ## 
>    dd bs=$bs of=/mnt/local/target.file \
## AND BE SURE DD'S FLAGS DECLARE RAW IO ##
>        conv=fsync oflag=direct,sync,nocache

## OUR RECEIVER'S WAITING; DIAL REMOTE TO BEGIN ##
% ssh [email protected] <<-REMOTECMD
## JUST REVERSED; NO RAW IO FLAGS NEEDED HERE, THOUGH ## 
>    dd if=/remote/source.file bs=$bs |\
>    lz4 -9 | nc local.target.domain $PORT
> REMOTECMD  

Sie könnten feststellen, dass Netcat beim Datentransport etwas schneller ist als SSH, wenn Sie es ausprobieren. Wie auch immer, die anderen Ideen wurden bereits aufgenommen, warum also nicht?

[BEARBEITEN]: Ich habe die Erwähnungen von lftp, scp und ssh in dem anderen Beitrag bemerkt und dachte, wir sprechen über eine Remote-Kopie. Local ist viel einfacher:

% bs=$(blockdev --getoptio /local/target/dev)
% dd if=/src/fi.le bs=$bs iflag=fullblock of=/tgt/fi.le \
>    conv=fsync oflag=direct,sync,nocache

[EDIT2]: Gutschrift, wo es fällig ist: Ich habe gerade bemerkt, dass mich ptman in den Kommentaren um etwa fünf Stunden geschlagen hat.

Auf jeden Fall könnten Sie $ bs mit einem Multiplikator auf Leistung einstellen. Bei einigen Dateisystemen muss es jedoch ein Vielfaches der Sektorgröße des Ziel-fs sein. Denken Sie also daran.

mikeserv
quelle
Auf meiner Maschine ist die Flagge --getiooptnicht--getoptio
Michael Mior
2

Das Problem ist, dass die Kopie Ihren Speicher mit Blöcken "im Flug" füllt und "nützliche" Daten verdrängt. Ein bekannter (und sehr schwer zu behebender) Fehler in der Linux-Kernel-Verarbeitung von E / A, um Geräte zu verlangsamen (in diesem Fall USB).

Vielleicht können Sie versuchen, das Kopieren zu parzellieren, z. B. durch ein Skript wie das folgende (Proof-of-Concept-Skizze, völlig ungetestet!):

while true do
  dd if=infile of=outfile bs=4096 count=... seek=... skip=...
  sleep 5
done

Anpassen seekund skipvon countjeder Runde. Es muss abgestimmt werden, countdamit nicht zu viel Speicherplatz belegt wird und der Speicher 5entleert wird.

vonbrand
quelle
2

Senken Sie das Limit für verschmutzte Seiten. Das Standardlimit ist Wahnsinn.

Erstellen Sie /etc/sysctl.d/99-sysctl.conf mit:

vm.dirty_background_ratio = 3
vm.dirty_ratio = 10

Führen Sie dann sysctl -p aus oder starten Sie neu.

Was passiert, ist, dass Daten schneller gelesen werden, als sie auf den Zieldatenträger geschrieben werden können. Wenn Linux Dateien kopiert, werden diese in den RAM eingelesen und die Seiten zum Schreiben an das Ziel als verschmutzt markiert. Verschmutzte Seiten können nicht ausgetauscht werden. Wenn der Quelldatenträger schneller als der Zieldatenträger ist und Sie mehr Daten kopieren, als über freien Arbeitsspeicher verfügen, wird durch den Kopiervorgang der gesamte verfügbare Arbeitsspeicher (oder zumindest die Obergrenze für fehlerhafte Seiten, die möglicherweise über der Obergrenze liegt) aufgebraucht verfügbarer RAM) und Hunger verursachen, da die verschmutzten Seiten nicht ausgetauscht werden können und saubere Seiten verwendet und als verschmutzt markiert werden, wenn sie freigegeben werden.

Beachten Sie, dass dies das Problem nicht vollständig lösen wird. Was Linux wirklich benötigt, ist eine Möglichkeit, die Erstellung schmutziger Seiten zu arbitrieren, sodass eine große Übertragung nicht den gesamten verfügbaren Arbeitsspeicher / alle zulässigen schmutzigen Seiten verschlingt.

alex.forencich
quelle
0

Dieses Problem hat nichts mit Fehlern oder Fehlern in der Hardware oder Software zu tun. Es ist nur Ihr Kernel, der versucht, nett zu Ihnen zu sein und Ihre Aufforderung zurückzugeben und im Hintergrund zu kopieren (es verwendet einen kerninternen Cache: mehr RAM, mehr Cache, Sie können dies jedoch einschränken, indem Sie irgendwo in / proc schreiben (dies wird jedoch nicht empfohlen). Flash-Laufwerke sind zu langsam, und während der Kernel darauf schreibt, können andere E / A-Vorgänge nicht schnell genug ausgeführt werden. ionicemehrmals in anderen antworten erwähnt ist ok. Aber haben Sie versucht, nur das Laufwerk mit -o synczu mounten, um eine Pufferung des Betriebssystems zu vermeiden? Es ist wahrscheinlich die einfachste Lösung da draußen.

orion
quelle
Nach dem Aktivieren von -o sync ist mein Internet schneller als das Schreiben auf dieses USB-Laufwerk. Was ich nicht verstehe, ist, warum der Kernel nicht nachverfolgt, wie schnell die Cache-Seiten geleert werden, und auf dieser Grundlage zukünftige Löschvorgänge plant. Es ist, als ob es immer auf voller Geschwindigkeit läuft, auch wenn dieses schlechte Laufwerk nicht mit der Geschwindigkeit mithalten kann. Aber das ist ein Thema für eine andere Frage, denke ich.
Antonone