Buat disk / salinan disk lebih lambat

28

Apakah ada metode memperlambat proses penyalinan di Linux?

Saya memiliki file besar, katakanlah 10GB, dan saya ingin menyalinnya ke direktori lain, tetapi saya tidak ingin menyalinnya dengan kecepatan penuh. Katakanlah saya ingin menyalinnya dengan kecepatan 1mb / s, tidak lebih cepat. Saya ingin menggunakan cpperintah Linux standar .

Apakah ini mungkin? (Jika ya, bagaimana?)

Sunting : jadi, saya akan menambahkan lebih banyak konteks ke apa yang saya coba capai.

Saya memiliki masalah pada sistem ArchLinux ketika menyalin file besar melalui USB (ke flashdisk, disk usb, dll). Setelah mengisi cache buffer usb, sistem saya berhenti merespons (bahkan mouse berhenti; hanya bergerak secara sporadis). Operasi penyalinan masih berlangsung, tetapi membutuhkan sumber daya 100% dari kotak. Ketika operasi penyalinan selesai, semuanya kembali normal - semuanya kembali responsif sempurna.

Mungkin itu adalah kesalahan perangkat keras, saya tidak tahu, tapi saya tahu saya punya dua mesin dengan masalah ini (keduanya ada di ArchLinux, satu adalah kotak desktop, kedua adalah laptop).

"Solusi" termudah dan tercepat untuk ini (saya setuju itu bukan solusi 'nyata', hanya 'hack' jelek) akan mencegah buffer ini dari mengisi dengan menyalin file dengan kecepatan tulis rata-rata dari drive USB, untuk saya itu sudah cukup.

antonone
sumber
7
Jika Anda ingin membatasi kecepatan salin disk-ke-disk dalam upaya untuk menjadi "baik" untuk proses I / O-terikat lainnya dalam sistem, Anda mungkin lebih baik mengambil keuntungan dari kemampuan kernel untuk mengatur penjadwalan I / O sebagai gantinya. Secara khusus, ionicedapat digunakan untuk memastikan bahwa proses penyalinan disk-ke-disk Anda dijadwalkan I / O pada prioritas yang lebih rendah daripada proses biasa.
Steven Monday
3
Ini adalah pertanyaan masalah XY klasik . Anda seharusnya bertanya mengapa desktop Anda menjadi tidak responsif saat menyalin file ke perangkat USB.
Michael Hampton
4
Linux sebenarnya memiliki buffer I / O yang sangat besar belakangan ini. Ukuran RAM telah tumbuh lebih cepat dari kecepatan penyimpanan massal. Mungkin Anda bisa melakukan penyalinan menggunakan dd (1) dan menyinkronkannya sehingga sebenarnya akan disinkronkan secara berkala alih-alih disangga? Dan penampil pipa (pv) memiliki opsi pembatasan laju. Sesuatu seperti cat file | pv -L 3k > outfile. Namun, keduanya tidak sama dengan menggunakan cp (1).
ptman
@MichaelHampton, ada beberapa topik yang belum terselesaikan tentang masalah ini di forum ArchLinux, jadi saya pikir saya akan mencoba mengatasinya dengan cara yang berbeda, hanya untuk membuatnya bekerja.
antonone
@antonone But Unix.SE bukan forum ArchLinux. Seseorang di sini mungkin punya solusi.
Izkata

Jawaban:

23

Anda dapat menekan pipa dengan pv -qL(atau cstream -tmenyediakan fungsi serupa)

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

-q menghapus pelaporan kemajuan stderr.

The -Lbatas dalam bytes.

Lebih lanjut tentang --rate-limit/-Lbendera dari 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.

Jawaban ini awalnya menunjuk throttletetapi proyek itu tidak lagi tersedia sehingga telah keluar dari beberapa sistem paket.

Mat
sumber
Jika cptidak dapat diperlambat, maka menggunakan perintah khusus adalah satu-satunya pilihan yang saya kira.
antonone
1
Kedengarannya terlalu rumit dibandingkan denganrsync
LinuxSecurityFreak
terlihat lebih rumit tetapi lebih bermanfaat bagi saya. Perlu menguji mekanisme penguncian file dan perlu memperlambat menyalin ke beberapa byte / s yang tampaknya tidak mungkin dengan rsync. Aku akan mencoba dan 'kucing' file melalui pipa throttle
cljk
sedih untuk mengatakan tetapi proyek ini sudah mati bugs.debian.org/cgi-bin/bugreport.cgi?bug=426891
cljk
1
@ cljk diperbarui ke pv. Terima kasih.
Matt
23

Alih-alih cp -a /foo /barAnda juga dapat menggunakan rsyncdan membatasi bandwidth yang Anda butuhkan.

Dari rsyncmanual:

--bwlimit=KBPS

membatasi I / O bandwidth; KBytes per detik

Jadi, perintah yang sebenarnya, juga menunjukkan kemajuan, akan terlihat seperti ini:

rsync -av --bwlimit=100 --progress /foo /bar
LinuxSecurityFreak
sumber
Ini terdengar seperti ide yang bagus untuk menyalin drive lama yang saya tidak ingin hajar.
jeremyjjbrown
Tidak berfungsi untuk membaca dari /dev/zeroatau/dev/random
cdosborn
rsync -a --bwlimit=1500 /source /destinationberfungsi dengan sempurna untuk menyalin folder raksasa dengan kecepatan 1,5 MB / s (yang merupakan pertukaran yang baik antara menghindari server yang melambat dan tidak mengambil terlalu banyak waktu)
lucaferrario
Sidenote: meskipun halaman manual mungkin mengatakan bahwa Anda dapat menggunakan huruf untuk unit, misalnya 20m, itu tidak didukung pada semua platform, jadi lebih baik tetap berpegang pada notasi KBytes.
Hubert Grzeskowiak
menyelamatkan hari saya! cgroup cgexec -g ... cp /in /outtidak berfungsi sepanjang waktu (dari terminal bekerja beberapa kali, dari script tidak pernah) dan saya tidak tahu mengapa ...
Aquarius Power
13

Saya menganggap Anda berusaha untuk tidak mengganggu aktivitas lainnya. Versi Linux terbaru termasuk ioniceyang memungkinkan Anda untuk mengontrol penjadwalan IO.

Selain memungkinkan berbagai prioritas, ada opsi tambahan untuk membatasi IO hingga saat-saat disk tidak digunakan. Perintah man ioniceakan menampilkan dokumentasi.

Coba salin file menggunakan perintah seperti:

ionice -c 3 cp largefile /new/directory

Jika dua direktori berada di perangkat yang sama Anda mungkin menemukan menautkan file melakukan apa yang Anda inginkan. Jika Anda menyalin untuk tujuan cadangan, jangan gunakan opsi ini. lnsangat cepat karena file itu sendiri tidak dapat disalin. Mencoba:

ln largefile /new/directory

Atau jika Anda hanya ingin mengaksesnya dari direktori di perangkat lain, cobalah:

ln -s largefile /new/directory
BillThor
sumber
apakah ionice berfungsi dengan baik di linux? saya membacanya hanya "meniru" pekerjaan dan tidak ada perbedaan nyata? +1 untuk tautan
Nick
1
@Nick Ketika saya sudah menggunakannya, sudah berperilaku seperti yang diharapkan. Proses yang saya gunakan ionice melambat secara signifikan, proses lain yang membutuhkan I / O mampu melakukan seperti yang diharapkan. Dengan beban I / O moderat dari proses lain, saya dapat secara efektif menangguhkan proses I / O tinggi dengan menerapkan 'kebaikan' maksimal seperti yang diharapkan. Setelah tidak ada I / O yang bersaing, proses terionisasi dilakukan seperti biasa.
BillThor
dengan file 400MB yang saya salin dari satu HD ke SSD, 10s pertama itu bekerja dengan sempurna, lalu tiba-tiba saya melihat saya memuat IO tinggi dan harus menunggu seperti mesin 1 menit beku: /. Saya memiliki masalah yang sama dengan cgroup menulis io throttle di mana ia bekerja kadang-kadang dan yang lain itu tidak akan berfungsi sama sekali.
Aquarius Power
7

Jika ionicesolusinya tidak cukup (mengapa) dan Anda benar-benar ingin membatasi I / O ke nilai absolut ada beberapa kemungkinan:

  1. yang mungkin paling mudah: ssh. Ini memiliki batas bandwidth bawaan. Anda akan menggunakan misalnya tar(bukan cp) atau scp(jika itu cukup baik; Saya tidak tahu bagaimana menangani symlink dan tautan keras) atau rsync. Perintah-perintah ini dapat menyalurkan data mereka ssh. Jika tarAnda menulis ke /dev/stdout(atau -) dan mengirimkannya ke sshklien yang mengeksekusi orang lain tardi sisi "remote".

  2. elegan tetapi tidak di kernel vanilla (AFAIK): Target mapper perangkat ioband. Ini, tentu saja, hanya berfungsi jika Anda dapat membuat umount sumber atau volume target.

  3. beberapa kesenangan yang ditulis sendiri: grep "^write_bytes: " /proc/$PID/iomemberi Anda jumlah data yang telah ditulis oleh suatu proses. Anda dapat menulis skrip yang dimulai cpdi latar belakang, tidur misalnya 1/10 detik, menghentikan cpproses latar belakang ( kill -STOP $PID), memeriksa jumlah yang telah ditulis (dan membaca? Tentang nilai yang sama dalam kasus ini), menghitung berapa lama cpharus berhenti untuk menurunkan laju transfer rata-rata ke nilai yang dimaksud, tidur untuk waktu itu, bangun cp( kill -CONT $PID), dan sebagainya.

Hauke ​​Laging
sumber
Ya, biasanya saya hanya menggunakan lftp untuk terhubung ke localhost via scp, dan membatasi bandwich dari sana.
antonone
5

Masalah Anda mungkin tidak dengan komputer Anda, karena itu mungkin baik-baik saja. Tetapi lapisan transisi flash USB memiliki prosesor sendiri yang harus memetakan semua tulisan Anda untuk mengkompensasi apa yang bisa sebanyak 90% chip flash rusak, siapa tahu? Anda membanjiri lalu membanjiri buffer, lalu membanjiri seluruh bus, lalu terjebak, bung - setelah semua, di situlah semua barang Anda. Ini mungkin terdengar kontra-intuisi tetapi yang Anda butuhkan adalah memblokir I / O - Anda harus membiarkan FTL mengatur langkahnya dan terus mengikuti.

(Saat meretas mikrokontroler FTL: http://www.bunniestudios.com/blog/?p=3554 )

Semua jawaban di atas harus berfungsi sehingga ini lebih merupakan "saya juga!" lebih dari yang lain: Aku benar-benar pernah ke sana, kawan. Saya memecahkan masalah saya sendiri dengan rsync's --bwlimit arg (2.5mbs tampaknya menjadi sweet spot untuk menjalankan tunggal, bebas kesalahan - apa pun lebih dan saya akan berakhir dengan kesalahan tulis-lindungi). rsync sangat cocok untuk tujuan saya karena saya bekerja dengan seluruh filesystem - jadi ada banyak file - dan hanya menjalankan rsync untuk kedua kalinya akan memperbaiki semua masalah run pertama (yang diperlukan ketika saya menjadi tidak sabar dan mencoba untuk melewati 2.5mbs).

Namun, saya rasa itu tidak cukup praktis untuk satu file. Dalam kasus Anda, Anda bisa melakukan pipe ke dd set ke raw-write - Anda dapat menangani input apa pun dengan cara itu, tetapi hanya satu file target pada satu waktu (meskipun file tunggal itu bisa menjadi perangkat blok keseluruhan, tentu saja).

## 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  

Anda mungkin menemukan netcat sedikit lebih cepat daripada ssh untuk transportasi data jika Anda mencobanya. Bagaimanapun, ide-ide lain sudah diambil, jadi mengapa tidak?

[EDIT]: Saya memperhatikan menyebutkan lftp, scp, dan ssh di pos lain dan berpikir kami sedang berbicara tentang salinan jarak jauh. Lokal jauh lebih mudah:

% 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]: Kredit yang jatuh tempo: baru sadar ptman mengalahkan saya dalam hal ini selama lima jam di komentar.

Tentunya Anda dapat menyetel $ bs untuk kinerja di sini dengan pengganda - tetapi beberapa sistem file mungkin mengharuskannya untuk menjadi kelipatan dari ukuran sektor fs jadi ingatlah itu.

mikeserv
sumber
Di komputer saya, benderanya --getiooptbukan--getoptio
Michael Mior
2

Masalahnya adalah bahwa salinan mengisi memori Anda dengan blok "dalam penerbangan," crowding out "berguna" data. Bug yang dikenal (dan sangat sulit untuk diperbaiki) di kernel Linux menangani I / O untuk memperlambat perangkat (USB dalam kasus ini).

Mungkin Anda bisa mencoba membagi salinannya, misalnya dengan skrip seperti berikut (sketsa proof-of-concept, sama sekali belum diuji!):

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

menyesuaikan seekdan skipoleh countsetiap putaran. Perlu disetel countagar tidak mengisi (terlalu banyak) memori, dan 5membiarkannya mengalir.

vonbrand
sumber
2

Turunkan batas halaman kotor. Batas defaultnya gila.

Buat /etc/sysctl.d/99-sysctl.conf dengan:

vm.dirty_background_ratio = 3
vm.dirty_ratio = 10

Kemudian jalankan sysctl -p atau reboot.

Apa yang terjadi adalah bahwa data sedang dibaca lebih cepat daripada yang dapat ditulis ke disk tujuan. Ketika linux menyalin file, yang dilakukannya adalah membacanya ke dalam RAM, kemudian menandai halaman sebagai kotor untuk menulis ke tujuan. Halaman kotor tidak dapat ditukar. Jadi jika disk sumber lebih cepat dari disk tujuan dan Anda menyalin lebih banyak data daripada RAM gratis, operasi penyalinan akan memakan semua RAM yang tersedia (atau setidaknya apa pun batas halaman kotornya, yang bisa lebih dari RAM yang tersedia) dan menyebabkan kelaparan karena halaman yang kotor tidak dapat ditukar dan halaman yang bersih digunakan dan ditandai kotor saat mereka dibebaskan.

Perhatikan bahwa ia tidak akan sepenuhnya menyelesaikan masalah ... apa yang benar-benar dibutuhkan linux adalah beberapa cara untuk menengahi pembuatan halaman kotor sehingga transfer besar yang terjadi tidak memakan semua RAM yang tersedia / semua halaman kotor yang diizinkan.

alex.forencich
sumber
0

Masalah ini tidak ada hubungannya dengan kesalahan atau kesalahan pada perangkat keras atau perangkat lunak, itu hanya kernel Anda mencoba bersikap baik kepada Anda dan memberikan prompt Anda kembali dan menyalin di latar belakang (menggunakan cache di-kernel: lebih banyak RAM, lebih banyak cache, tetapi Anda dapat membatasi dengan menulis di suatu tempat di / proc - meskipun tidak direkomendasikan). Flash drive terlalu lambat dan ketika kernel menulis di atasnya, operasi IO lainnya tidak dapat dilakukan dengan cukup cepat. ionicedisebutkan beberapa kali dalam jawaban lain ok. Tetapi apakah Anda sudah mencoba memasang drive -o syncuntuk menghindari buffering OS? Itu mungkin solusi paling sederhana di luar sana.

orion
sumber
Setelah mengaktifkan -o sinkronisasi, Internet saya lebih cepat daripada kecepatan tulis ke drive USB ini. Yang tidak saya mengerti adalah mengapa kernel tidak melacak seberapa cepat halaman cache semakin memerah, dan menjadwalkan flushes di masa depan berdasarkan itu. Sepertinya selalu berjalan dengan kecepatan penuh, bahkan jika drive yang buruk ini tidak dapat mengimbangi kecepatan. Tapi itu topik untuk pertanyaan lain kurasa.
antonone