Bash 脚本 - 忽略挂起服务器的方法

Bash 脚本 - 忽略挂起服务器的方法

我编写了一个脚本,可以在后台运行 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 个脚本畅通无阻。

相关内容