我曾尝试并行化我正在使用的脚本,但到目前为止,GNU Parallel 非常具有挑战性。
我有 2 个文件 - 一个包含运行命令的主机,另一个包含命令的参数。以下是示例数据:
$ cat workers.host
[email protected]
[email protected]
[email protected]
[email protected]
$ cat paths
/usr/local/jar/x/y/ jarxy
/usr/local/jar/z/y/ jarzy
/usr/local/jar/y/y/ jaryy
/usr/local/far/x/y/ farxy
/usr/local/jaz/z/z/ jazzz
/usr/local/mu/txt/ana/ acc01
/usr/local/jbr/x/y/ accxy
为了处理这个问题,我使用了以下脚本:
#!/bin/bash
echo "Run this on 192.168.130.10";
DATA=`date +%F`
DDAY=`date +%u`
DOMBAC='nice tar cpzf'
readarray -t hosts < workers.host
len=${#hosts[@]};
processed=0;
while read -r -a line; do
let hostnum=processed%len;
ssh ${hosts[$hostnum]} -i /root/.ssh/id_rsa "$DOMBAC - ${line[0]}" > "/data/backup/$DDAY/${line[1]}_${DATA}_FULL.tgz"
let processed+=1;
done < paths
这种方法效果很好,但是需要在一台又一台机器上逐步处理。主机的性能非常强大,而网络在这里不是问题,所以我想尽可能地并行化。例如,在每个主机上运行 4 个 tar 命令实例,并通过 ssh 将输出传输到正确命名的文件中。我对并行完全迷茫了--results
--sshloginfile
……我最终试图实现的是让每个主机上运行 4 个作业,每个作业都有不同的参数(例如,主机 2 不会覆盖主机 1 已经执行的操作)。这可以在 GNU Parallel 中完成吗?
答案1
首先,您需要知道如何从一行输入中提取多个参数:
cat paths | parallel --colsep ' ' echo {2} == {1}
(我注意到一些 {2} 可以从 {1} 生成。如果总是如此,您可能需要研究 {= =};但那是另一个问题的故事)。
要远程运行作业,您可以使用-S
:
cat paths | parallel --colsep ' ' -S server echo {2} == {1}
要控制在远程服务器上运行的作业数,请使用-j
:
cat paths | parallel --colsep ' ' -j4 -S server echo {2} == {1}
要获取本地存储的输出,--return --cleanup
可以使用:
cat paths | parallel --return {2} --cleanup --colsep ' ' -j4 -S server echo {2} == {1} '>' {2}
由于您希望将输出存储在本地的不同目录中,因此您需要使用 /./ 技巧:
cat paths | parallel --return my/local/dir/./{2} --cleanup --colsep ' ' -j4 -S server echo {2} == {1} '>' {2}
要使用特殊ssh
命令,请使用--ssh
:
parallel --ssh "ssh -i $HOME/.ssh/id_rsa.pub -lroot" --return {2} --cleanup --colsep ' ' -j4 -S server echo {2} == {1} '>' {2}
要在多台服务器上运行,请--slf
使用-S
:
parallel --slf hosts.txt --ssh "ssh -i $HOME/.ssh/id_rsa.pub -lroot" --return {2} --cleanup --colsep ' ' -j4 echo {2} == {1} '>' {2}
因此,你的命令总的来说可能如下所示:
parallel --slf hosts.txt --ssh "ssh -i $HOME/.ssh/id_rsa.pub -lroot" --return /data/backup/$DDAY/./{2}_${DATA}_FULL.tgz --cleanup --colsep ' ' -j4 "$DOMBAC - {1} > {2}_${DATA}_FULL.tgz"
答案2
您可以使用并行来实现这一点,但我认为这对于您要实现的目标来说有点过头了。相反,我只需使用后台作业来(几乎)同时运行这些命令。
为了在对现有脚本进行最少更改的情况下实现此目的,我们需要做的就是在每个任务运行时将其置于后台(使用 & 运算符执行此操作)。为了防止出现孤立进程,我们应该确保脚本在所有作业完成之前不会退出,这可以通过 bash 内置命令来实现wait
。 jobs 命令将输出正在运行的任务列表(可能不是全部,根据执行时间,有些任务可能在您到达该位置之前已经完成)。
我也不确定为什么您要使用不带参数的 nice 命令 - 我相信如果没有参数,它所做的就是打印已启动任务的相对优先级,我想这可能是您的意图。
这是脚本的修改版本,包含以下更改
#!/bin/bash
echo "Run this on 192.168.130.10";
DATA=`date +%F`
DDAY=`date +%u`
DOMBAC='nice tar cpzf'
readarray -t hosts < workers.host
len=${#hosts[@]};
processed=0;
while read -r -a line; do
let hostnum=processed%len;
ssh ${hosts[$hostnum]} -i /root/.ssh/id_rsa "$DOMBAC - ${line[0]}" > "/data/backup/$DDAY/${line[1]}_${DATA}_FULL.tgz" &
let processed+=1;
done < paths
jobs
wait