
大量の大きなファイル (数百のファイル、それぞれ数百 MB) があり、それらを複数のプログラムにパイプしてフィルタリングおよび変換する必要があります。複数の CPU コアを利用して、各ファイルで同じパイプのインスタンスを複数実行しています (最大 100 コアまで実行でき、パイプの一部として ssh を使用することもできます。これにより、回答に違いが生じる可能性があります)。各パイプを監視したいので、pv
それを使用しています。以下は、私が持っているものの最小限の例です。
$ pv file-001.gz | gunzip | xz > file-001.xz
1.58GB 0:00:02 [ 713MB/s] [=================================>] 100%
実際には、パイプ内では、SSH 経由で他のマシンにデータを渡したり、それらのマシンのフィルターにデータをパイプしたりといった他の処理もいくつか行いますが、パイプは常にメイン ホスト上の新しいファイルへのリダイレクトで終了します。また、パイプ内のどのステージでもデータ セット全体は必要ありません。行単位またはチャンク単位で操作できます。
現在、パイプの各インスタンスごとに個別のターミナル ウィンドウが必要です。 私がやりたいのは、単一のターミナル/シェルでパイプの n 個の並列インスタンスを開始し、各 pv インスタンスからの出力を独自の行で取得することです。 次のようになります。
1.48GB 0:00:54 [ 704MB/s] [===============================> ] 97% ETA 00:00:06
1.58GB 0:01:00 [ 713MB/s] [=================================>] 100%
0.75GB 0:00:31 [ 709MB/s] [================> ] 50% ETA 00:00:29
n の値は、ターミナル ウィンドウに収まる行数、たとえば 3 ~ 50 行程度になります。進行状況レポートの正確な形式は、速度、完了率、経過時間、推定残り時間が含まれていれば、重要ではありません。 を使用することも重要ではなくpv
、簡単にインストールできる限り、他のプログラムや、単純なシェル (bash が望ましい) を使用してもかまいません。ただし、パイプの一部が何らかの理由でクラッシュした場合に、メソッドが時々壊れたパイプを処理できることは重要です。また、ジョブが終了し (正常または失敗)、未処理のファイルが残っているたびに、新しいジョブを開始したいと思います。
これを実行する方法について何かアイデアはありますか?
すでに試してみましたGNU パラレルしかし、その ssh 機能では、各入力ファイルが最初にリモート ホストに転送され、次に処理されて、結果が返されることを前提としているようですが、関係するデータの量と各処理ノード上のスペースの量が限られているため、これを回避したいと考えています。
答え1
これを実行する方法について何かアイデアはありますか?
いいえ。
pvには-cと-Nオプションがあり、これを使えば望みどおりのことができるはずです。
$ pv -cN source access.log | gzip | pv -cN gzip > access.log.gz
source: 760MB 0:00:15 [37.4MB/s] [=> ] 19% ETA 0:01:02
gzip: 34.5MB 0:00:15 [1.74MB/s] [ <=> ]
しかし、その機能を複数のパイプラインに適用する方法がわかりません
しかし、pvのマニュアルページを見ると、次のことがわかります。
(tar cf - . \
| pv -n -s $(du -sb . | awk '{print $1}') \
| gzip -9 > out.tgz) 2>&1 \
| dialog --gauge 'Progress' 7 70
したがって、小さなウィンドウのクラスターで進行状況を表示することが許容される限り、これを拡張して、複数のタスクを並行して実行することができます。Xdialog を試してみます。
現在、パイプの各インスタンスごとに別のターミナルウィンドウが必要です。
私が言いたいのは、対話的に多数のターミナル ウィンドウを開く必要はなく、 1 つのスクリプトで多数のダイアログ ボックスを開くことができるということです。
答え2
--pipe
GNU Parallel を調べましたか?
cat bigfiles* | pv | parallel --pipe -S server1,server2 'cat | process_pipe'
(強調のため猫も含めます)
デフォルトのブロックサイズは 1 MB ですが、--block で調整できます。
-- 1-1 対応の編集 --
上記に基づいて、次のような 1 対 1 対応が得られます。
parallel --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*
(強調のため猫も含めます)
これは最適とは言えません。内側の並列処理は兄弟処理を認識しないため、server2 よりも server1 で多くの処理が実行される可能性があるからです。これを回避する 1 つの方法は、外側の並列処理で -j1 を使用することですが、内側の並列処理に最初のサーバー用のブロックしかない場合は最適ではありません。言い換えると、ワークロードのバランスを完全に取るには、これを少し調整する必要があるかもしれません。場合によっては、--load 100% などを使用する必要があるかもしれません。
--- 編集: クラッシュに対処する ---
エラーが返された場合はprocess_pipe
、コマンドをさらに 2 回再試行する必要があります。
parallel --retries 3 --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*