分享一個在Linux下模擬多線程的並發腳本,使用這個腳本可以同時批量在定義數量的服務器上執行相關命令,比起普通for/while循環只能順序一條一條執行的效率高非常多,在管理大批服務器時非常的實用。
以下腳本功能是通過scp(也可選rsync)向上千台服務器傳更新包,腳本運行后同時在后台有50個scp進程向服務器傳包。
#!/bin/bash
ip=`cat iplist.txt|grep -v "#"|awk '{print $1}'` #過濾服務器IP
dir='/usr/local/src' #目標路徑
thead_num=50 #自定義並發數,根據自身服務器性能或應用調整大小,開始千萬別定義太大,避免管理機宕機
tmp_fifo_file="/tmp/$$.fifo" #以進程ID號命名管道文件
mkfifo $tmp_fifo_file #創建臨時管道文件
exec 4<>$tmp_fifo_file #以讀寫方式打開tmp_fifo_file管道文件,文件描述符為4,也可以取3-9任意描述符
rm -f $tmp_fifo_file #刪除臨時管道文件,也可不刪除
for ((i=0;i<$thead_num;i++)) #利用for循環向管道中輸入並發數量的空行
do
echo "" #輸出空行
done >&4 #輸出重導向到定義的文件描述符4上
for i in $ip #循環所有要執行的服務器
do
read -u4 #從管道中讀取行,每次一行,所有行讀取完畢后執行掛起,直到管道有空閑的行
{
scp -P 1000 $1 $i:$dir #所有要批量執行的命令都放在大括號內,scp是一個簡單實例,可替換任意其他命令及命令組,1000為服務器端的端口
sleep 3 #暫停3秒,給系統緩沖時間,達到限制並發進程數量
echo "" >&4 #再寫入一個空行,使掛起的循環繼續執行
}& #放入后台執行
done
wait #等待所有后台進程執行完成
exec 4>&- #刪除文件描述符
exit 0
--------------------------------低調的分割線------------------------------------
如果管理機與其他服務器沒有建立ssh信任,也可將expect自動應答命令添加到並發腳本的循環體當中,修改如下:
#!/bin/bash
ip=`cat iplist.txt|grep -v "#"|awk '{print $1}'`
dir='/usr/local/src'
answer="yes" #定義yes/no應答變量
passwd="123456" #服務器密碼
thead_num=50
tmp_fifo_file="/tmp/$$.fifo"
mkfifo $tmp_fifo_file
exec 4<>$tmp_fifo_file
rm -f $tmp_fifo_file
for ((i=0;i<$thead_num;i++))
do
echo ""
done >&4
for i in $ip
do
read -u4
{
expect <<EOF
set timeout -1
spawn scp -P 1000 $1 $i:$dir
expect "(yes/no)?" {
send "$answer\r"
expect "Password:"
send "$passwd\r"
} "Password:" {send "$passwd\r"} "*host" {exit 1}
expect eof
EOF
sleep 3
echo "" >&4
}&
done
wait
exec 4>&-
exit 0