1、前置条件
- 所有节点需配置SSH免密登录
- 节点列表文件 hosts.txt 格式示例,此文件需要放置在和脚本同一目录下:
192.168.1.100
192.168.1.101
192.168.1.102
2、创建脚本
创建文件,在此我命名为parallel_exec.sh ,以下是完整代码。把代码复制进脚本文件即可。
#!/bin/bash
LOG_DIR="logs/$(date +%Y%m%d_%H%M%S)"
CONCURRENCY=3
MAX_RETRY=3
prepare_env() {
# 创建日志目录(-p 表示递归创建)
mkdir -p "$LOG_DIR"
# 备份当前的标准输出(stdout)和标准错误(stderr)
exec 3>&1 4>&2
# 设置退出陷阱:当脚本退出时,恢复 stdout 和 stderr
trap 'exec 1>&3 2>&4' EXIT
}
run_parallel() {
local cmd="$1" # 接收用户传入的命令
local i=0 # 任务计数器
while read host; do # 逐行读取 hosts.txt 中的主机名
((i++)) # 每读取一个主机,计数器+1
echo "[INFO] Processing $host (Task $i)"
{
retry=0
until [ $retry -ge $MAX_RETRY ]; do # 重试循环
timestamp=$(date "+%Y-%m-%d %T")
echo "[$timestamp] Executing on $host"
ssh -o ConnectTimeout=10 "$host" "$cmd" \
> "$LOG_DIR/$host.log" \ # 标准输出重定向
2>&1 && break || { # 标准错误重定向
((retry++))
echo "[ERROR] Retry $retry for $host"
sleep 1
}
done
} & # 将整个任务放入后台执行
if ((i % CONCURRENCY == 0)); then # 控制并发数量
wait # 等待当前所有后台任务完成
fi
done < hosts.txt # 从 hosts.txt 读取主机列表
wait # 最终等待所有后台任务结束
}
main() {
prepare_env
run_parallel "$1"
}
main "$@"
3、脚本说明
① CONCURRENCY=3
-
含义:并发执行的节点数量限制为3个
-
作用:
- 同时最多有3个节点在执行命令(通过
&将任务放入后台) - 防止因并发量过高导致SSH连接风暴或网络拥堵
- 当任务数超过3时,后续任务会排队等待前面的任务完成(通过wait实现)
- 同时最多有3个节点在执行命令(通过
-
示例:
如果集群有20个节点,脚本会分4轮执行(5个/轮),每轮完成后进入下一轮。 -
修改建议:
- 小集群:可设为节点总数(如
CONCURRENCY=10) - 大集群:建议设为5-10(避免资源争抢)
- 通过参数动态传入(需修改脚本逻辑)
- 小集群:可设为节点总数(如
② MAX_RETRY=3
-
含义:单个节点命令执行失败时,最多重试3次
-
作用:
- 自动重试因网络抖动、节点负载高等临时问题导致的失败
- 每次重试间隔1秒(
sleep 1) - 若3次均失败,则记录错误并继续执行下一个任务
-
示例:
若某节点执行systemctl restart nginx失败,脚本会尝试再执行3次。 -
修改建议:
- 临时性故障(如网络问题):设为3-5次
- 关键操作(如配置更新):设为0(禁用重试,立即报错)
- 通过参数动态传入(需修改脚本逻辑)
4、使用
首先赋予脚本可执行权限:
chmod +x parallel_exec.sh
例子:向集群分发pip3的安装命令:
./parallel_exec.sh "pip3 install pandas"
注意:在大多数 Linux 系统中 ,有些命令属于别名,如 “ll” ,当通过 ssh 执行命令时(如 ssh 192.168.1.100 “ll”),会启动一个 非交互式 shell,它默认不会加载别名定义,导致 ll 无法识别。./parallel_exec.sh “ll” 是会执行失败的,要改成./parallel_exec.sh "ls -l" 。另外所有命令都是在集群根目录/root下执行的。

463

被折叠的 条评论
为什么被折叠?



