本文目录导读:

在Shell脚本中实现并行发布策略,主要有以下几种常用方法:
使用 & 后台运行 + wait 等待
最简单的并行执行方式:
#!/bin/bash
# 并行发布函数
deploy_service() {
local service=$1
local version=$2
echo "[$(date +%H:%M:%S)] 开始发布 $service (版本: $version)"
sleep $((RANDOM % 5 + 2)) # 模拟发布过程
echo "[$(date +%H:%M:%S)] $service 发布完成"
return $((RANDOM % 2))
}
# 定义要发布的服务列表
services=("service-a" "service-b" "service-c" "service-d")
version="v2.1.0"
# 并行发布所有服务
echo "开始并行发布..."
for svc in "${services[@]}"; do
deploy_service "$svc" "$version" &
pids+=($!) # 保存后台进程PID
done
# 等待所有发布完成
failed=0
for i in "${!pids[@]}"; do
wait "${pids[$i]}"
if [ $? -ne 0 ]; then
echo "${services[$i]} 发布失败"
((failed++))
fi
done
# 输出结果汇总
echo "===== 发布结果 ====="
echo "总共: ${#services[@]} 个服务"
echo "成功: $(( ${#services[@]} - failed )) 个"
echo "失败: $failed 个"
[ $failed -eq 0 ] && exit 0 || exit 1
控制并发数量(信号量机制)
当服务很多时,需要限制并行数量:
#!/bin/bash
# 使用文件描述符控制并发数
concurrent_deploy() {
local max_jobs=$1 # 最大并行数
local services=("${!2}") # 服务列表
local version=$3
# 创建命名管道用于控制并发
tmpdir=$(mktemp -d)
mkfifo "$tmpdir/fifo"
exec 3<>"$tmpdir/fifo"
# 初始化信号量
for ((i=0; i<max_jobs; i++)); do
echo >&3
done
# 并行发布
for svc in "${services[@]}"; do
read -u 3 # 获取信号量
{
echo "[$(date +%H:%M:%S)] 开始发布 $svc"
sleep $((RANDOM % 3 + 1))
echo "[$(date +%H:%M:%S)] $svc 完成"
echo >&3 # 释放信号量
} &
done
# 等待所有完成
wait
exec 3>&-
rm -rf "$tmpdir"
}
# 使用示例
services=("svc-1" "svc-2" "svc-3" "svc-4" "svc-5")
concurrent_deploy 3 services[@] "v2.0.0"
使用 GNU Parallel 工具
更专业的并行处理工具:
#!/bin/bash
# 安装: apt-get install parallel 或 brew install parallel
deploy_one_service() {
local service=$1
local version=$2
echo "开始发布 $service"
# 模拟发布步骤
echo " 1. 拉取镜像: $service:$version"
sleep 1
echo " 2. 停止旧版本"
sleep 1
echo " 3. 启动新版本"
sleep 1
echo " 4. 健康检查"
sleep 1
echo "$service 发布完成"
}
export -f deploy_one_service # 导出函数供parallel使用
# 定义服务列表
SERVICES="service-a service-b service-c service-d"
VERSION="v3.0.0"
# 并行执行,控制并发数
echo "使用GNU Parallel并行发布..."
echo "$SERVICES" | tr ' ' '\n' | parallel -j 4 deploy_one_service {} $VERSION
# 带进度显示
echo "$SERVICES" | tr ' ' '\n' | parallel --progress -j 3 deploy_one_service {} $VERSION
带错误处理和回滚策略
更完整的生产环境发布脚本:
#!/bin/bash
# 配置
MAX_PARALLEL=3
VERSION=${1:-"latest"}
DEPLOY_LOG="/var/log/deploy_$(date +%Y%m%d_%H%M%S).log"
# 服务配置
declare -A SERVICES
SERVICES=(
["api-gateway"]="8080"
["user-service"]="8081"
["order-service"]="8082"
["payment-service"]="8083"
["notification-service"]="8084"
)
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$DEPLOY_LOG"
}
# 健康检查
health_check() {
local service=$1
local port=$2
local retries=10
for ((i=1; i<=retries; i++)); do
if curl -sf "http://localhost:$port/health" > /dev/null 2>&1; then
return 0
fi
sleep 2
done
return 1
}
# 发布单个服务
deploy_service() {
local service=$1
local port=$2
local version=$3
local result_file=$4
log "[$service] 开始部署..."
# 模拟部署步骤
{
log "[$service] 拉取镜像: $service:$version"
sleep 2
# 模拟失败(10%概率)
if [ $((RANDOM % 10)) -eq 0 ]; then
log "[$service] ❌ 部署失败"
echo "$service:FAILED" >> "$result_file"
return 1
}
log "[$service] 启动新版本..."
sleep 3
# 健康检查
if health_check "$service" "$port"; then
log "[$service] ✅ 部署成功"
echo "$service:SUCCESS" >> "$result_file"
return 0
else
log "[$service] ❌ 健康检查失败,触发回滚"
# 执行回滚操作
echo "$service:ROLLBACK" >> "$result_file"
return 1
fi
}
}
# 主函数
main() {
local result_file=$(mktemp)
local pids=()
log "开始并行发布,版本: $VERSION"
log "最大并行数: $MAX_PARALLEL"
# 使用队列控制并发数
local queue=()
local running=0
for service in "${!SERVICES[@]}"; do
port=${SERVICES[$service]}
# 等待,直到当前并行数小于最大限制
while [ $running -ge $MAX_PARALLEL ]; do
for pid in "${pids[@]}"; do
if ! kill -0 $pid 2>/dev/null; then
wait $pid
((running--))
fi
done
sleep 1
done
# 启动新的部署进程
deploy_service "$service" "$port" "$VERSION" "$result_file" &
pids+=($!)
((running++))
done
# 等待所有进程完成
wait
# 汇总结果
log "===== 发布汇总 ====="
local success=0
local failed=0
local rollback=0
while IFS= read -r line; do
service=${line%:*}
status=${line#*:}
case $status in
SUCCESS) ((success++)) ;;
FAILED) ((failed++)) ;;
ROLLBACK) ((rollback++)) ;;
esac
log " $service: $status"
done < "$result_file"
rm -f "$result_file"
log "统计: 成功=$success, 失败=$failed, 回滚=$rollback"
if [ $failed -eq 0 ] && [ $rollback -eq 0 ]; then
log "✅ 所有服务发布成功"
return 0
else
log "⚠️ 部分服务发布异常"
return 1
fi
}
# 执行
main "$@"
使用 xargs 实现并行
简单快速的并行方案:
#!/bin/bash
# 并行发布函数
deploy() {
local service=$1
echo "发布 $service..."
sleep $((RANDOM % 3 + 1))
echo "$service 完成"
}
export -f deploy
# 服务列表
cat << EOF > services.txt
service-a
service-b
service-c
service-d
service-e
EOF
# 并行执行,-P 控制并行数
cat services.txt | xargs -I {} -P 3 bash -c 'deploy "$@"' _ {}
最佳实践建议
- 错误处理:每个并行任务都要捕获错误并进行处理
- 日志记录:集中收集所有并行任务的日志
- 资源限制:根据服务器资源合理设置并发数
- 超时控制:为每个任务设置超时时间
- 回滚机制:单个任务失败时,最好有自动回滚能力
# 超时控制示例
deploy_with_timeout() {
local timeout=$1
shift
timeout $timeout "$@" &
pid=$!
wait $pid 2>/dev/null
return $?
}
# 使用
deploy_with_timeout 300 deploy_service "svc-a" "v1.0.0"
选择哪种方式取决于你的具体需求:
- 简单场景:使用
&+wait - 需要控制并发:使用管道信号量或 GNU Parallel
- 生产环境:使用完整的错误处理和回滚方案