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()带有archive_name可选number_of_attempts参数的函数。这包含您的第二个while循环,但替换$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
     )
 }

在函数内部,我们使用了一个子shell,(...)带有两个退出语句。
该函数将返回子shell 的退出值,要么为真(rsync 成功),要么为假(尝试次数过多)。

然后我们将其与存档创建结合起来:

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在脚本末尾添加而不是管道,但它具有捕获后台进程的所有输出的良好效果。

现在,我已经忽略了一个重要方面,那就是可以并行运行的作业数量。这将合理地扩展,但实际上维护一个作业队列会更好。超过一定数量,添加更多工作将开始减慢速度,此时您将不得不添加工作计数器和工作限制。达到作业限制后,停止启动更多create_and_transfer_archive作业,直到流程完成。

如何跟踪这些工作是一个单独的问题。

于 2013-10-03T21:00:51.787 回答