Eu escrevi um script bash que faz algo similar, esgotando os núcleos da CPU local. Quando um núcleo é liberado, ele chama um novo cálculo, até que os cálculos sejam concluídos. Eu também tenho um pouco de experiência de script bash com ssh (requer um ssh-key sem senha, se você estiver confortável com esse risco de segurança). Este é um exemplo pessoal fora do contexto, mas a idéia é que é um script bash que faz um loop dinamicamente com base no tempo de processamento e varia os parâmetros. A variável $ CORES, no seu caso, precisa ser preenchida com os servidores disponíveis, e precisamos encontrar uma maneira de rastreá-los para saber para qual ligar em seguida.
Loop () {
# looping function over all runs with the same header, multi-threaded per core.
CMDINIT="$CMD"
for i in "$TREEIN"/"$NAME"*.root # loop over all the existing raw runs of that name
do
# name of the output file and path, eg Tree/30s_production/30s_production-1001.root
OUTPUT='echo $i | sed "s#$TREEIN/##" |sed "s#$NAME#$TREEOUT/$NAME/$NAME-#" '
INFILE='echo $i | sed 's$.*/$$'' # name of the input file name, eg 30s_production1001.root
if [ ! -e $OUTPUT ];then # only run if the output file does not exist (won't overwrite existing data)
if [ ! $Cflag ];then # only call the program if we aren't cleaning
echo "Outputting to $OUTPUT..."
RUNNO='echo $INFILE | sed "s/$NAME//" | sed 's/\..*//'' # get the run number
# there is a way to do this using the Run function? Seems trickier with backgrounding, getting PID, and so on
CMD="$CMDINIT -R $RUNNO"
printf "Executing run with the command:\n\t$CMD\n"
$CMD & PIDS="$PIDS $!" # call run on the run number in background w/o renice
#$CMD & PIDS="$PIDS $!" && sudo renice -n 0 -p $! # call run on the run number in background, renice to -10
while [ 'jobs | wc -l' -eq $CORES ] # only run one run command per core
do
jobs > /dev/null # without this the while loop doesn't seem to refresh?
sleep 1 # keep waiting until run is not running on a core
done
fi
else # the output file exists -- should never happen as we check NeedClean first, but anyway, safer
echo "$OUTPUT exists, please run clean!"
exit 1
fi
done
}
Existem duas partes 'inteligentes' aqui (ou 'hacks', se você preferir). Um é o loop while que verifica o número de jobs
e aguarda até que algo esteja livre. (Meu presente do loop é baseado em um parâmetro, mas isso é fácil de ajustar.) Aqueles jobs
são os que estão dentro do script bash, e é assim que ele alcança o conceito para repetir novamente em uma condição em que um job é concluído ; lembre-se de que isso será idêntico se o trabalho for local ou remoto: um comando para chamar um comando SSH será o mesmo que um trabalho local (embora, talvez seja necessário coletar todos os resultados posteriormente de todos os servidores ou servidores gravando os dados localmente, etc, conforme necessário). Outro aspecto crítico para mim é como quando $ CMD é chamado, ele também coloca o número do processo em um contador chamado $ PIDS. Isso permite que uma armadilha control_c no script bash local consiga eliminar todos os processos filhos, o que incluiria processos gerados em todos os seus 100 servidores, caso você decida encerrar antes; a conseqüência de não rastrear isso é tão horrível quanto você pode imaginar!
Se você quiser verificar o script principal, está aqui: link
Precisamos modificar a definição da variável $ CMD para algo na ordem de
CMD=ssh '$USER@$HOST' /path/to/executable
Depois disso, devemos aplicar dinamicamente os sinalizadores ao executável para controlar os diferentes parâmetros (também podemos enviá-los em um arquivo de texto para cada servidor via scp, mas, finalmente, precisamos rastreá-los de qualquer maneira e a diferença não é significativo para mim). Meu caso define a maioria dos parâmetros uma vez, mas não há motivo para que não possamos chamar isso toda vez que um servidor for aberto. Parece com isso, onde eu uso sinalizadores, mas isso é trivial para definir conjuntos de spool de arquivos de texto com parâmetros. Incrementar uma variável de contagem em um campo awk para cada campo, em ordem, até que seja esgotado, etc, e redefini-la na função Loop toda vez que a próxima variável de contagem for incrementada, seqüencialmente através de todas as permutações de parâmetros.
SetFlags () {
# base command
CMD="./run"
# add options based on final flags
[ $Rflag ] && CMD="$CMD -R $Rval"
[ $Bflag ] && CMD="$CMD -B"
[ $Hflag ] && CMD="$CMD -H $Hval"
[ $Iflag ] && CMD="$CMD -I $Ival"
[ $rflag ] && CMD="$CMD -r"
[ $dflag ] && CMD="$CMD -d"
[ $sflag ] && CMD="$CMD -s"
[ $xflag ] && CMD="$CMD -x"
[ $pflag ] && CMD="$CMD -p"
[ $tflag ] && CMD="$CMD -t"
}
Tenho permissão para receber e-mails após respostas, pois considero essa uma pergunta interessante, mas preciso de mais tempo para pensar em acompanhar os hosts quando eles são desalocados. Desculpe eu não respondi a questão toda ainda!