我编写了一个脚本,可以在后台运行 1000 多个服务器上的命令。有时脚本会挂在其中一台服务器上。如果/当服务器在运行脚本时挂起(由于平均负载较高),该命令也可能在该服务器上挂起。有没有办法跳过该主机,以便脚本可以转到下一个主机并继续运行?
我强调了我的脚本的两个主要功能,但没有给出“ConnectTimeout”和等待关键字。
exec_ssh()
{
for i in `cat $file`
do
ssh -q -o "StrictHostKeyChecking no" -o "NumberOfPasswordPrompts 0" -o ConnectTimeout=2 $i $command 2>>/dev/null &
if wait $!; then
echo "" >> /dev/null
else
echo "$i is not reachable over SSH or passwordless authentication is not setup on the server" >> /tmp/not_reachable
fi
done >/tmp/output.csv &
run_command()
{
export -f exec_ssh
export command
nohup bash -c exec_ssh &>>$log_file &
}
答案1
您编写的脚本会保持同时运行所有远程命令,但为了使用wait
它,将显式等待后台任务完成。在您描述的高负载服务器的情况下,这意味着您的ssh
命令没有超时,而只是需要很长时间才能完成,因此脚本完全按照您的要求执行。 ConnectTimeout
当您能够成功建立ssh
连接时就没有意义了。
如果您确实想使用此类脚本而不是为分布式远程执行而设计的工具,例如安西布尔,我可能会修改你的脚本如下:
exec_ssh() {
while read file; do
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$i" "$command" 2>>/dev/null & then
echo "$i is not reachable via non-interactive SSH or remote command threw error - exit code $?" >> /tmp/not_reachable
fi
done < "$file" > /tmp/output.csv &
}
run_command() {
export -f exec_ssh
export command
nohup bash -c exec_ssh &>> "$log_file" &
}
还可能值得考虑将“我可以通过 SSH 连接到主机”测试和“我可以完成工作吗”测试分开:
if ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" true; then
# connection succeeded
if ! ssh -q -o BatchMode=yes -o ConnectTimeout=2 "$host" "$command" & then
echo "Remote command threw $?"
fi
else
echo "SSH threw $?"
fi
答案2
随着您的本地和远程命令变得越来越复杂,您很快就会因为试图将所有这些都塞进一个连贯的脚本而不知所措,并且由于有数百或数千个后台进程,即使有强大的后台进程,您也可能会遇到资源争用问题。本地机器。
您可以使用 来控制这一点xargs -P
。我通常将这样的任务分成两个脚本。
本地.sh
一般来说,这个脚本有一个参数,即主机名,并执行任何必要的验证、飞行前任务、日志记录等。例如:
#!/bin/bash
hostname=$1
# simple
cat remote.sh | ssh user@$hostname
# sudo the whole thing
cat remote.sh | ssh user@$hostname sudo
# log to files
cat remote.sh | ssh user@$hostname &> logs/$hostname.log
# or log to stdout with the hostname prefixed
cat remote.sh | ssh user@$hostname 2>&1 | sed "s/^/$hostname:/"
远程.sh
您想要远程运行的脚本,但现在您不必将其塞入引用的单行代码中并处理引用逃脱的地狱。
实际命令
cat host_list.txt | xargs -P 16 -n 1 -I {} bash local.sh {}
在哪里:
-P 16
将分叉最多 16 个子进程-n 1
每个命令只提供一个参数-I {}
将用参数代替{}
[ 此处不必要,但对于构造更复杂的 xargs 调用可能有用。
这样,即使您的本地或远程脚本之一挂起,您仍然可以让其他 15 个脚本畅通无阻。