Bash脚本多SSH会话并行执行问题及优化方案咨询
更优的Bash SSH会话并行化方案及问题解决
问题分析
你当前的脚本直接在循环中将每个SSH任务后台执行,同时发起30+个SSH连接时,可能触发本地/远程系统的连接限制、并发会话上限,或是因未等待任务完成导致部分进程异常终止,最终出现用户创建随机遗漏的情况。虽然调整了net.core.somaxconn和maxlogins,但这些参数未必覆盖所有限制(比如远程服务器sshd的并发配置、本地进程数限制等)。
优化方案
1. 控制并发数,避免瞬间资源过载
全量后台启动会瞬间压满系统资源,建议用分批并行或并发数控制的方式,降低连接失败概率:
用xargs控制并发
将服务器列表转换为每行一个,通过xargs -P指定最大并发数(示例设为10,可根据系统承受能力调整):
SSH="/bin/ssh -o ConnectTimeout=60 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -p 61313" # 将空格分隔的SERVERS转为每行一个,再启动并发任务 echo "$SERVERS" | tr ' ' '\n' | xargs -I {} -P 10 bash -c ' echo "adding user user1 in $1" '"$SSH"' $1 "sudo echo \"user1:pass1:1313:1015::/home/user1:/bin/rbash\" | sudo newusers" ' _ {}
用GNU Parallel(更灵活)
如果系统已安装parallel,可以更简洁地控制并发,还支持失败重试:
SSH="/bin/ssh -o ConnectTimeout=60 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -p 61313" # 定义单服务器处理函数 add_user() { server=$1 echo "adding user user1 in $server" $SSH "$server" "sudo echo \"user1:pass1:1313:1015::/home/user1:/bin/rbash\" | sudo newusers" } # 导出函数和变量给parallel使用 export -f add_user export SSH # 启动15个并发任务,可加--retries 2实现失败重试 echo "$SERVERS" | tr ' ' '\n' | parallel -j 15 add_user
2. 确保任务执行完成并捕获错误
原脚本注释掉了wait,可能导致脚本在后台SSH任务完成前就退出,部分进程被强制终止。即使控制并发,也要确保所有任务执行完毕:
SSH="/bin/ssh -o ConnectTimeout=60 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -p 61313" # 存储所有后台进程PID pids=() for i in $SERVERS do echo "adding user user1 in $i" $SSH $i "sudo echo \"user1:pass1:1313:1015::/home/user1:/bin/rbash\" | sudo newusers" & pids+=($!) done # 等待所有进程完成并检查退出状态 for pid in "${pids[@]}" do wait $pid if [ $? -ne 0 ]; then echo "任务PID $pid 执行失败" fi done
3. 优化SSH连接参数,减少资源消耗
- 移除
-tt参数:批量执行命令无需强制分配伪终端,该参数会增加额外资源开销,甚至导致连接异常。 - 启用SSH连接复用:通过ControlMaster复用已建立的连接,大幅减少重复创建会话的资源消耗:
# 先创建控制目录 mkdir -p ~/.ssh/controlmasters SSH="/bin/ssh -o ConnectTimeout=60 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -p 61313 \ -o ControlMaster=auto -o ControlPath=~/.ssh/controlmasters/%h:%p:%r -o ControlPersist=60s"
4. 检查远程服务器限制
除本地参数外,需排查远程服务器的以下配置:
sshd_config中的MaxStartups(控制并发SSH连接数,默认值为10:30:100,可适当调大)sshd_config中的MaxSessions(单个SSH连接的最大会话数)- 远程系统的
ulimit限制,比如用户最大进程数
25个用户批量处理建议
如果要为25个用户分别在30+台服务器创建,可将用户信息整理为列表,结合连接复用和并发控制批量执行:
# 用户信息列表,每行一条 users=( "user1:pass1:1313:1015::/home/user1:/bin/rbash" "user2:pass2:1314:1015::/home/user2:/bin/rbash" # ... 剩余23个用户信息 ) SSH="/bin/ssh -o ConnectTimeout=60 -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -p 61313 \ -o ControlMaster=auto -o ControlPath=~/.ssh/controlmasters/%h:%p:%r -o ControlPersist=60s" # 定义单服务器处理所有用户的函数 process_server() { server=$1 echo "处理服务器 $server 的所有用户" for user_info in "${users[@]}" do user=$(echo "$user_info" | cut -d: -f1) echo "在 $server 创建用户 $user" echo "$user_info" | $SSH "$server" "sudo newusers" done } export -f process_server export SSH users # 启动10个并发任务处理服务器 echo "$SERVERS" | tr ' ' '\n' | parallel -j 10 process_server
内容的提问来源于stack exchange,提问作者Giancarlo D
相关产品推荐
相关产品推荐

