1

私はいくつかのことを行う以下のスクリプトを持っています...

#!/bin/bash

# Script to sync dr-xxxx
# 1. Check for locks and die if exists
# 2. CPIO directories found in cpio.cfg
# 3. RSYNC to remote server
# 5. TRAP and remove lock so we can run again

if ! mkdir /tmp/drsync.lock; then
        printf "Failed to aquire lock.\n" >&2
        exit 1
fi
trap 'rm -rf /tmp/drsync.lock' EXIT  # remove the lockdir on exit

# Config specific to CPIO
BASE=/home/mirxx
DUMP_DIR=/usrx/drsync
CPIO_CFG="$BASE/cpio.cfg"

while LINE=: read -r f1 f2
do
  echo "Working with $f1"
  cd $f1
  find . -print | cpio -o | gzip > $DUMP_DIR/$f2.cpio.gz
  echo "Done for $f1"
done <"$CPIO_CFG"

RSYNC=/usr/bin/rsync # use latest version
RSYNC_BW="4500" # 4.5MB/sec
DR_PATH=/usrx/drsync
DR_USER=root
DR_HOST=dr-xxxx
I=0
MAX_RESTARTS=5 # max rsync retries before quitting
LAST_EXIT_CODE=1

while [ $I -le $MAX_RESTARTS ]
do
  I=$(( $I + 1 ))
  echo $I. start of rsync
  $RSYNC \
           --partial \
           --progress \
           --bwlimit=$RSYNC_BW \
           -avh $DUMP_DIR/*gz \
               $DR_USER@$DR_HOST:$DR_PATH
  LAST_EXIT_CODE=$?
  if [ $LAST_EXIT_CODE -eq 0 ]; then
        break
  fi
done

# check if successful
if [ $LAST_EXIT_CODE -ne 0 ]; then
  echo rsync failed for $I times. giving up.
else
  echo rsync successful after $I times.
fi

上記で変更したいのは、この行です..

  find . -print | cpio -o | gzip > $DUMP_DIR/$f2.cpio.gz

上記の行を変更して、フィードを取得する CPIO_CFG のすべてのエントリに対して並列プロセスを開始するように検討しています。最後に & を使用する必要があると思いますか? 安全対策を実施する必要がありますか?

上記のコマンドを変更して、cpio.cfg ファイルで $f3 経由で渡すことができる除外リストも含めることは可能ですか。

以下のコードの場合..

while [ $I -le $MAX_RESTARTS ]
do
  I=$(( $I + 1 ))
  echo $I. start of rsync
  $RSYNC --partial --progress --bwlimit=$RSYNC_BW -avh $DUMP_DIR/*gz $DR_USER@$DR_HOST:$DR_PATH
  LAST_EXIT_CODE=$?
  if [ $LAST_EXIT_CODE -eq 0 ]; then
        break
  fi
done

ここで同じことですが、$DUMP_DIR/*.gz にある .gz ファイルに対して複数の RSYNC スレッドを実行することは可能ですか?

上記により、スクリプトの速度が大幅に向上すると思います。ボックスはかなり頑丈です(AIX 7.1、48コア、192GB RAM)。

ご協力ありがとうございました。

4

1 に答える 1

1

元のコードは従来のバッチ キューです。少しリーンな考え方を加えましょう...

実際のワークフローは、一連のディレクトリを圧縮された cpio 形式で変換および転送することです。ディレクトリ/アーカイブ間に依存関係がないと仮定すると、アーカイブと転送を作成するための単一のアクションを作成できるはずです。

スクリプトを関数に分割すると、意図がより明確になるはずです。

まず、と オプションを引数として関数transfer_archive()を作成します。これには 2 番目のループが含まれていますが、 に置き換えられます。詳細は練習問題として残します。archive_namenumber_of_attemptswhile$DUMP_DIR/*gz$archive_name

 function transfer_archive {
     typeset archive_name=${1:?"pathname to archive expected"} 
     typeset number_of_attempts=${2:-1}

     (
         n=0
         while 
             ((n++))
             ((n<=number_of_attempts))
         do
             ${RSYNC:?} 
                 --partial \
                 --progress \
                 --bwlimit=${RSYNC_BW:?} \
                 -avh ${archive_name:?} ${DR_USER:?}@${DR_HOST:?}:${DR_PATH:?} && exit 0
         done
         exit 1
     )
 }

関数内では、2 つの exit ステートメントを持つサブシェル(...を使用します。 この関数は、サブシェルの終了値を true (rsync が成功した) または false (試行回数が多すぎる) のいずれかで返します。)

次に、それをアーカイブの作成と組み合わせます。

function create_and_transfer_archive {
    (
        # only cd in a subshell - no confusion upstairs
        cd ${DUMP_DIR:?Missing global setting} || exit

        dir=${1:?directory}
        archive=${2:?archive}

        # cd, find and cpio must be in the same subshell together
        (cd ${dir:?} && find . -print | cpio -o ) |
             gzip > ${archive:?}.cpio.gz || return # bail out 

        transfer_archive ${archive:?}.cpio.gz
    )
 }

最後に、メイン ループはすべてのディレクトリを並行して処理します。

while LINE=: read -r dir archive_base
do
    (
        create_and_transfer_archive $dir ${archive_base:?} &&
            echo $dir Done || echo $dir failed            
    ) &
done <"$CPIO_CFG" | cat

のパイプの代わりに、スクリプトの最後にcat追加することもできますがwait、バックグラウンド プロセスからのすべての出力をキャプチャするという優れた効果があります。

ここで、1 つの重要な側面について説明しました。それは、並行して実行できるジョブの数です。これは適度に拡張されますが、実際にはジョブ キューを維持する方がよいでしょう。特定の数を超えると、さらにジョブを追加すると速度が低下し始めます。その時点で、ジョブ カウンターとジョブ制限を追加する必要があります。ジョブの制限に達したら、create_and_transfer_archiveプロセスが完了するまでジョブの開始を停止します。

これらのジョブを追跡する方法は、別の問題です。

于 2013-10-03T21:00:51.787 に答える