GNU Parallel: Linuxタスクの処理速度を10倍に「加速」させる方法

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

16コアのサーバーなのにスクリプトの実行に午後いっぱいかかる?

数千枚の画像の圧縮や数十GBেরサーバーログの解析に、何時間も待たされたことはありませんか?もしそうなら、この記事はまさにあなたのためのものです。エンジニアになりたての頃、私はBashで単純なforループをよく使っていました。ある時、16コアのサーバーで20,000枚の画像を変換する必要がありました。結果として、スクリプトはたった1つのコアでしか動作せず、残りの15コアは…お休み状態。結局、ターミナルの画面をぼーっと眺めているだけで午後が終わってしまいました。

GNU Parallelを知ったことで、すべてが変わりました。これは司令塔のような役割を果たし、既存のすべてのCPUコアにタスクを自動的に「切り分け」てくれます。コマンドを1つずつ順番に実行するのではなく、サーバーの性能をフル回転させることで、マシンの構成にもよりますが、作業を5倍、さらには10倍も速く完了させることができます。

GNU Parallelを「一瞬」でインストールする

# Ubuntu / Debian
sudo apt update && sudo apt install parallel -y

# CentOS / RHEL / Fedora
sudo dnf install parallel -y

# Arch Linux
sudo pacman -S parallel

仕組みを理解するために、まずは簡単なコマンドを試してみましょう:

parallel echo ::: 1 2 3 4 5

ここで、:::記号はコマンドと入力を区切るために使われます。1、2、3、4、5を亀のような速さで順番に表示する代わりに、Parallelはそれらを異なるプロセスに投入し、同時に処理します。

より実用的な例を見てみましょう。約10GBある50個の圧縮ログファイル(.gz)を至急解凍する必要があるとします。

ls *.gz | parallel gunzip

1ファイルずつゆっくりgunzipする代わりに、上記のコマンドは複数のプロセスを同時に起動します。CPUの負荷(Load)は急上昇しますが、その分、待ち時間はわずか数分に短縮されます。

なぜGNU Parallelはxargsやforループよりも「優れている」のか?

xargs -Pでも並列実行できるのでは?」と思うかもしれません。実際、Parallelの方がはるかにスマートで安全です。長年VPSを管理してきた経験から、私がParallelを優先する理由は次の3つの「強み」があるからです:

  • 出力順序の維持: xargsの場合、ターミナルへの出力結果は終了した順にバラバラになります。Parallelは結果をまとめ、入力と同じ順序で返してくれます。これは、データをレポートファイルに出力する際に非常に重要です。
  • スペースを含むファイル名への対応: ファイル名に空白が含まれていると、Bashスクリプトを書く際に「悪夢」となります。Parallelは、-0や複雑なIFSなどのトリックを使わずに、これを非常にスムーズに処理します。
  • SSH経由のタスク分散: これが最強の機能です。SSH経由で3〜4台の他のサーバーにコマンドを飛ばし、サーバークラスター全体の計算リソースを同時に活用できます。

3つの「実戦的」な活用シナリオ

1. Web用画像のバッチリサイズ

フォルダ内にある5GBの画像すべてをImageMagickで800pxにリサイズする場合、Parallelを使えば大幅な時間を節約できます:

ls *.jpg | parallel convert {} -resize 800x800 {.}__resized.jpg

解説:

  • {}: 現在のファイル名を表す変数。
  • {.}: 拡張子を除いたファイル名(新しいファイルを簡単に作成できます)。

2. 高速データダウンロード

links.txtファイルに100個のURLリストがありますか?wgetで1つずつダウンロードする代わりに、この方法を試してみてください:

cat links.txt | parallel -j 10 wget {}

-j 10パラメータは、Parallelに対して最大10個のスレッドを同時に実行するように指示します。ダウンロード速度は大幅に向上しますが、DDoS攻撃と間違えられてターゲットサーバーからIPブロックされないよう、数値を大きくしすぎないように注意してください!

3. ログのエラー検索を高速化

数百個の古い圧縮ログファイルから「ERROR」というキーワードを探す必要がある場合、私はよくこれを使います:

ls access.log.*.gz | parallel "zgrep 'ERROR' {} >> errors.txt"

リソース管理:サーバーを「ダウン」させないために

本番環境(Production)で稼働中のサーバーで作業する場合、コマンドを適当に投げてCPUリソースを100%占有させるわけにはいきません。コツは、コア数に応じてジョブの数を制限することです:

parallel --jobs 50% ... # 利用可能なコアの50%のみを使用

また、タスクが重くエラーが発生しやすい場合は、--joblog機能を使ってステータスを監視しましょう:

parallel --joblog my_tasks.log ./my_script.py ::: input1 input2 input3

万が一サーバーがダウンしたり、作業を一時停止したい場合は、次回実行時に--resumeフラグを追加するだけです。Parallelはmy_tasks.logの内容を確認し、やり残した部分だけを実行してくれます。長時間かかるタスクには非常に便利です。

並列実行における「手痛い教訓」

Parallelは非常に強力ですが、実体験から注意すべき点が3つあります:

  1. ディスクI/Oのボトルネックに注意: 大容量ファイルのコピーなど、データの書き込みが非常に重いタスクの場合、並列実行するとシングルタスクよりも遅くなることがあります。ディスクの読み書きヘッドが常に動き回り、I/O Waitが高くなるためです。
  2. RAMの管理: 生成される各プロセスは、一定量のRAMを消費します。16GBのサーバーで、1つ1GBのRAMを消費するスレッドを50個走らせれば、システムは確実にフリーズします。
  3. 常にDry-runで試す: Enterキーを押して本番実行する前に、--dry-runフラグを付けてどのようにコマンドが実行されるかを確認しましょう。一歩間違えてデータを失うことを防ぎます。
parallel --dry-run echo {} ::: test1 test2

まとめると、GNU ParallelはLinuxでプロフェッショナルな仕事をしたいなら必須のツールです。退屈で時間のかかる作業を、驚くほど迅速かつ効率的に変えてくれます。次のプロジェクトでぜひ活用してみてください。そのパフォーマンスの高さに驚くはずです。

Share: