並列スクリプトプロセス

並列スクリプトプロセス

IPごとにApacheアクセスログを解析したいです。次のコードを使用しましたが、ほぼ90秒かかりました。

grep "^$CLIENT_IP" /var/log/http/access.log > /tmp/access-$CLIENT_IP.log

その後、次の選択肢を試しました。

sed -i -e "/^$CLIENT_IP/w /tmp/access-$CLIENT_IP.log" -e '//d' /var/log/http/access.log

この作業も60秒以上かかりました。

解決すべきIPは1200個です。実行時間を短縮するために並列性を達成する方法があるかどうかを知りたいです。

ベストアンサー1

おそらく、テキストファイルのIPアドレスを使用して、すべてのIPアドレスのシェルループでこれを行うとします。はい、IPアドレスsedごとに1回呼び出すとgrep速度が遅くなります。

sed代わりによく準備すれば一度は運が続くこともある。

まずスクリプトを作成する必要があります。sedIPアドレスが1行に1つずつ含まれるファイルでこれを行います。ip.list

sed -e 'h' \
    -e 's/\./\\./g' \
    -e 's#.*#/^&[[:blank:]]/w /tmp/access-#' \
    -e 'G' \
    -e 's/\n//' \
    -e 's/$/.log/' ip.list >ip.sed

これは、sed各IPアドレスに対して

  1. アドレスを「予約済みスペース」(の追加バッファsed)にコピーします。
  2. .「パターンスペース」(入力行)を\.(ポイントを正しく一致させるためにコードではこれを行いません)に変更します。
  3. パターンスペースの前に追加^します。[[:blank:]]/w /tmp/access-
  4. 改行文字を挟んで、予約済みスペースからパターンスペースに変更されていない入力行を追加します。
  5. 改行文字を削除します。
  6. .log行の末尾に追加し、結果を暗黙的に印刷します。

以下を含むファイルの場合

127.0.0.1
10.0.0.1
10.0.0.100

sedこれでスクリプトが生成されます。

/^127\.0\.0\.1[[:blank:]]/w /tmp/access-127.0.0.1.log
/^10\.0\.0\.1[[:blank:]]/w /tmp/access-10.0.0.1.log
/^10\.0\.0\.100[[:blank:]]/w /tmp/access-10.0.0.100.log

IPアドレスの後にスペース文字(スペースまたはタブ)が一致する必要があります。それ以外の場合は、ログエントリがファイル10.0.0.100に保存されます/tmp/access-10.0.0.1.log。あなたのコードはこれを無視します。

その後、繰り返しなしでログファイルで使用できます。

sed -n -f ip.sed /var/log/http/access.log

私は同じスクリプトでsed1200個のファイルを書くことをテストしたことがありません。うまくいかない場合は、次のawkバリエーションを試してください。


同様の回避策は、awkまずIPアドレスを配列に読み込み、それを各行に一致させることです。これには一度のawk呼び出しが必要です。

awk 'FNR == NR  { list[$1] = 1; next }
     $1 in list { name = $1 ".log"; print >>name; close name }' ip.list /var/log/http/access.log

ここではawkIPリストとログファイルの両方を提供します。NR == FNRまだ最初のファイル(リスト)を読んでいることがわかったら、IPlist番号を連想配列のキーとして追加し、次の入力行に進みます。

条件が満たされない場合は、FNR == NR2番目のファイル(ログファイル)から読み込み、入力行の最初のフィールドがキーフィールドであるかどうかをテストしますlist(これは正規表現一致ではなく純粋な文字列比較です)。その場合は、適切な名前のファイルに行を追加します。

出力ファイルを閉じるときは注意が必要です。そうしないと、開いているファイル記述子が不足する可能性があります。したがって、追加するために開いたり閉じたりするファイルはたくさんありますが、awkIPアドレスごとに1回呼び出す(またはその問題のユーティリティ)よりも高速です。


これがあなたにうまくいくか、おおよそのランタイムが何であるかを知りたいです。私は非常に小さなデータセットでのみこれらのソリューションをテストしました。


もちろん、私たちはあなたのアイデアに同意し、grepシステムに複数のインスタンスを並列に投げて、それを無差別に代入することができます。

IPアドレスのドットが正確に一致しなかったことを無視し、おそらく

xargs -P 4 -n 100 sh -c '
    for n do
        grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
    done' sh <ip.list

ここでは、短いシェルスクリプトにxargs一度に最大100のIPアドレスがファイルから提供されます。ip.list4つの並列スクリプト呼び出しをスケジュールします。

ショートシェルスクリプト:

for n do
    grep "^$n[[:blank:]]" /var/log/http/access.log >"/tmp/access-$n.log"
done

xargsこれは、コマンドラインに提供されている100個のIPアドレスを繰り返し、grep4つのループが並列に実行されることを除いて、使用したものとほぼ同じコマンドを適用します。

保持しているCPUの数を増やす-P 4か、それに関連しています。各並列インスタンスが同じディスクから読み書きできる-P 16ため、スピードアップは線形ではない可能性があります。grep

-Pこの回答のすべての内容は、タグを除くxargsすべてのPOSIXシステムで実行できる必要があります。-Pフラグはxargs非標準ですが、xargsGNUシステムとBSDシステムで実装されています。

おすすめ記事