ウェブサイト検索

Linuxで大量または何百万ものファイルをコピーする5つの速い方法


あなたは何年もcpでファイルをコピーしてきました。そして、もしあなたが50GBのバックアップを移動したり、ディレクトリツリーをリモートサーバーに同期したりしている場合、その習慣は毎日静かに時間、可視性、回復可能性を失わせています。

cpコマンドは、まさに一つのことをうまく行います:ファイルをコピーすることです。しかし、進行状況の表示も、速度制限も、再開サポートも、組み込みのチェックサム確認も提供しません。

数メガバイトのローカルコピーであれば問題ありませんが、ネットワークリンク越しに40GBのデータベースダンプを送信したり、20万個の小さなファイルを新しいディスクにコピーしたりする瞬間には、点滅するカーソルと無言の祈り以上のものが欲しくなります。

大きなコピーにおいてcpが不十分な理由

cpはPOSIX標準なので、常に存在しますが、これはシンプルさのために作られており、大量データの操作向けではありません。ファイルを読み取り、並列処理なしで順次書き込み、差分ロジックもなく、端末へのフィードバックもありません。

プロセスが中断されると、例えば停電、SSHのタイムアウト、誤ってCtrl+Cを押すなどの場合、再開できないため、最初から完全にやり直す必要があります。

そして、もしリモートホストにコピーしている場合、それはscpのような別の手順を通じて行っており、同じ全か無かの動作を持ち、信頼できるLAN上で必要ない場合でも暗号化のオーバーヘッドが追加されます。

もしあなたが定期的に大量のデータセットをサーバー間で移動していて、それでも cp を使っているなら、これをチームと共有してください - 以下のツールは、誰かの午前2時のやり直しを救ってくれます。

rsync: 再開可能なファイル転送のための定番ツール

rsyncは、cpでは不十分なときに最初に学ぶべきツールです。なぜなら、ソースと宛先の間の差分のみをコピーし、再開をサポートし、ローカルでもSSH経由でも動作するからです。

まだインストールされていない場合は、インストールしてください:

sudo apt install rsync         [On Debian, Ubuntu and Mint]
sudo dnf install rsync         [On RHEL/CentOS/Fedora and Rocky/AlmaLinux]
sudo apk add rsync             [On Alpine Linux]
sudo pacman -S rsync           [On Arch Linux]
sudo zypper install rsync      [On OpenSUSE]    
sudo pkg install rsync         [On FreeBSD]

sudo プレフィックスはコマンドをルート権限で実行します。これはパッケージのインストールに必要です。基本的なローカルファイルのコピーでは sudo は必要ありませんが、システムディレクトリの同期には必要です。

標準的なローカルディレクトリのコピーはこのようになります:

rsync -av --progress /source/directory/ /destination/directory/

出力:

sending incremental file list
database/
database/dump_2024.sql
    2,147,483,648 100%   98.45MB/s    0:00:20 (xfr#1, to-chk=0/2)

sent 2,147,483,909 bytes  received 35 bytes  102.24MB/s total size is 2,147,483,648

フラグの内訳:

  • -a はアーカイブモードを有効にし、権限、タイムスタンプ、シンボリックリンク、およびディレクトリ構造を再帰的に単一のフラグで保持します。
  • -v は転送する際に各ファイル名を表示します。
  • --progress は、ファイルごとの転送速度と進行状況のパーセンテージをリアルタイムで表示します。

<code>/source/directory/</code> の後のスラッシュは重要です:スラッシュがある場合、<code>rsync</code> はディレクトリの内容をコピーします。スラッシュがない場合、<code>rsync</code> はディレクトリ自体を宛先のサブディレクトリとしてコピーします。これを間違えると、期待していたものではなく <code>/destination/directory/directory/</code> になってしまいます — 初めての人によくある間違いです。

SSHを介してリモートサーバーにコピーするには、構文はほとんど同じです:

rsync -av --progress /local/path/ user@remote-ip:/remote/path/

remote-ip をサーバーのIPアドレスに置き換えてください。IPアドレスは ip a で確認できます。

ip a

もし転送が途中で止まった場合は、同じコマンドをもう一度実行すると、rsyncはちょうど中断したところから再開し、すでに正常に転送されたファイルはスキップします。

rsyncについてより深く学ぶことは時間の価値があります。Pro TecMintのSSHコースでは、SSHベースの転送、キー認証、リモートrsyncのパターンを54章に渡って解説しています。

pv:ファイル転送に進捗バーを追加

pv(Pipe Viewer)は、Unix のパイプ内に配置され、転送速度、経過時間、および推定完了時間を表示する小さなユーティリティです。cp や rsync を置き換えるものではありませんが、それらをラップします。

インストールする:

sudo apt install pv         [On Debian, Ubuntu and Mint]
sudo dnf install pv         [On RHEL/CentOS/Fedora and Rocky/AlmaLinux]
sudo apk add pv             [On Alpine Linux]
sudo pacman -S pv           [On Arch Linux]
sudo zypper install pv      [On OpenSUSE]    
sudo pkg install pv        [On FreeBSD]

最も簡単な使い方は、ライブプログレスバー付きで単一の大きなファイルをコピーすることです:

pv /source/large-file.iso > /destination/large-file.iso

出力:

8.35GiB 0:01:22 [ 104MiB/s] [=========>          ] 63% ETA 0:00:47

その出力は、ディスクが実際にどれだけ速く書き込んでいるかを正確に示しており、これは単なるcpでは決して得られない情報です。また、pvを圧縮にパイプして、一度にアーカイブとコピーを行うこともできます:

pv /source/large-file.tar | gzip > /destination/large-file.tar.gz

パイプラインを分解する:

  • `pv /source/large-file.tar` は、ソースファイルを読み取り、スループットをターミナルに報告します。
  • gzip はストリームをリアルタイムで圧縮します。
  • `> /destination/large-file.tar.gz` は、圧縮された出力を指定した宛先に書き込みます。

dd: ディスククローンおよび生コピーのためのパワーツール

ddはより低レベルのツールであり、すでにすべてのLinuxシステムにインストールされています。これは生のブロックを読み書きするため、ディスク全体やパーティションのクローン作成、ディスクイメージの作成、生ディスクのスループットテストに適したツールです。

ddのリスクは、出力パスのタイプミスが警告なしに誤ったディスクを消去してしまう可能性があることです。したがって、実行する前に常にターゲットを二重に確認してください。

典型的なディスク間クローンは次のようになります:

sudo dd if=/dev/sda of=/dev/sdb bs=64K conv=noerror,sync status=progress

出力:

50033664512 bytes (50 GB, 47 GiB) copied, 623.847 s, 80.2 MB/s

フラグの内訳:

  • `if=/dev/sda` は入力ファイル、つまりソースディスクを設定します。
  • `of=/dev/sdb` は出力ファイル、つまり宛先ディスクを設定します。実行する前に `lsblk` でこれが正しいデバイスであることを確認してください。
  • bs=64K はブロックサイズを64キロバイトに設定します。これは、大きな連続読み取りにおいて、デフォルトの512バイトのブロックサイズよりもはるかに高速です。
  • `conv=noerror,sync` は、読み取りエラーが発生しても `dd` に処理を続行させ、障害ブロックをゼロで埋めるよう指示し、コピー全体を停止させないようにします。
  • `status=progress` は数秒ごとにライブスループットを出力します。これは coreutils 8.24 で追加されたもので、古いシステムではこのフラグは利用できず、進行状況のレポートを取得するには手動で USR1 シグナルを送信する必要があります。

警告: dd は確認を求めません。もし if と of を入れ替えると、ソースディスクの内容を宛先に書き込み、コピーしようとしたデータを破壊してしまいます。

もしこれが痛いddのミスからあなたを救ったなら、ディスクイメージの作業を始めたばかりの誰かに伝えてあげてください。

parallel + rsync:数百万の小さなファイルをより速くコピー

rsync は大きなファイルでは高速ですが、転送ごとにシングルスレッドです。数十万の小さなファイルがあるディレクトリ、例えば Node.js の node_modules ディレクトリ、メールスプール、または写真ライブラリでは、ファイルごとのオーバーヘッドが実際のデータ転送時間を上回るため、rsync は予想以上に時間がかかることがあります。

GNU Parallel は、複数の rsync ジョブを同時に実行することでこれを解決します。

sudo apt install parallel         [On Debian, Ubuntu and Mint]
sudo dnf install parallel         [On RHEL/CentOS/Fedora and Rocky/AlmaLinux]
sudo apk add parallel             [On Alpine Linux]
sudo pacman -S parallel           [On Arch Linux]
sudo zypper install parallel      [On OpenSUSE]    
sudo pkg install parallel         [On FreeBSD]

次に、大きなディレクトリツリー全体で並列にrsyncを実行します:

find /source/directory -mindepth 1 -maxdepth 1 -type d | \
  parallel -j 4 rsync -a {} /destination/directory/

パイプラインを分解する:

  • `find /source/directory -mindepth 1 -maxdepth 1 -type d` は、ソースの最上位のサブディレクトリを一覧表示します。
  • parallel -j 4 は、各サブディレクトリごとに1つずつ、4つの rsync ジョブを同時に実行します。したがって、-j は CPU の数とディスクの速度に合わせて調整してください。
  • rsync -a {} /destination/directory/ は各サブディレクトリを送信先に同期します。ここで {} は各ディレクトリ名に置き換えられます。

50万個の小さなファイルがあるディレクトリでは、この方法は通常、単一のrsyncコールと比べてコピー時間を60〜70%短縮します。これは、I/Oキューが一度に一つのファイルを待つのではなく、常に埋まった状態を保つためです。

Pro TecMintの『100以上の必須Linuxコマンド』コースでは、find、パイプ、およびコマンドラインの構成について詳しく解説しており、このようなパイプラインを作成することに慣れたい場合に役立ちます。

SHA256チェックサムでファイルの整合性を確認する

これらのツールのどれも、コピーが実際に正常に完了したかを確認しなければあまり重要ではありません。重要なコピーには、転送が完了した後にチェックサム比較を行ってください。

SHA256 はほとんどの用途に最適な選択です:

sha256sum /source/large-file.iso /destination/large-file.iso

出力:

a3b4c1d2e5f6...  /source/large-file.iso
a3b4c1d2e5f6...  /destination/large-file.iso

もし両方のハッシュが一致すれば、コピーはバイト単位で完全です。もし異なる場合は、ディスクエラー、ネットワークの破損、またはソースに書き込みを行っている他のプロセスとの競合条件など、転送中に何か問題が発生したことを意味し、そのデータを信用する前に再度コピーする必要があります。

結論

cp は設定ファイルを一つのディレクトリから別のディレクトリに移動するには問題ありませんが、本格的なシステム管理作業、例えば大規模なバックアップ、リモート同期、ディスククローン、数百万の inode を含むディレクトリなどには適していません。

あなたは rsync を使用する必要があります。これは再開と差分転送を提供し、pv は可視性を提供し、dd はブロックレベルの制御を提供し、parallel rsync は小さいファイルが多いディレクトリでスループットを提供します。

今すぐ試すべき最良の方法は、システム上の大きなディレクトリを選び、まず cp で一度コピーし、その後 rsync -av --progress で再度コピーして、出力と所要時間を比較することです。これにより、今まで見逃していたものがすぐに分かり、rsync の操作に関する筋肉記憶もそこから身についていきます。

本番環境で大量のファイルをコピーする際の頼りになるツールは何ですか?また、これらのツールでは足りず、別の方法を使わざるを得なかった状況に遭遇したことはありますか?コメント欄で教えてください。