Проблемы при цикле по серии команд ssh-ed
У меня есть ряд серверных машин, на которых я хочу запустить одну и ту же команду. Каждая команда занимает несколько часов, и (хотя я запускаю команды с использованием nohup и настраиваю их для выполнения в фоновом режиме), мне приходится ждать завершения каждой из них, прежде чем начнутся следующие. Вот как я это настроил:
На хост-машинах:
for i in {1..9}; do ssh RemoteMachine${i} ./RunJobs.sh; done
Где RunJobs.sh на каждой удаленной машине:
source ~/.bash_profile
cd AriadneMatching
for file in FileDirectory/Input_*;
do
nohup ./Executable ${file} &
done
exit
Кто-нибудь знает способ, которым я не должен ждать, пока каждая работа не закончится до следующего запуска? Или, альтернативно, лучший способ сделать это, у меня есть ощущение, что я делаю это довольно неоптимально. Ура, Джек
4 ответа
Решение для локальной машины
На основе параллельного ssh
# pssh -P --par 2 --hosts RemoteMachines /opt/RunJobs.sh
или же:
# pssh -i --par 2 --hosts RemoteMachines /opt/RunJobs.sh
Объяснение параметров:
-P
--print
Display output as it arrives. This option is of limited usefulness
because output from different hosts are interleaved.
-i
--inline
Display standard output and standard error as each host completes.
-p parallelism
--par parallelism
Use the given number as the maximum number of concurrent connections.
-h host_file
--hosts host_file
Read hosts from the given host_file.
На основе ансибл
# ansible --forks 2 -i RemoteMachines '*' -m command -a /opt/RunJobs.sh
Объяснение параметров:
-f NUM, --forks=NUM
Level of parallelism. NUM is specified as an integer, the default is 5.
-i PATH, --inventory=PATH
The PATH to the inventory hosts file, which defaults to /etc/ansible/hosts.
-m NAME, --module-name=NAME
Execute the module called NAME.
-a 'ARGUMENTS', --args='ARGUMENTS'
The ARGUMENTS to pass to the module.
Командный модуль принимает имя команды, за которым следует список разделенных пробелами аргументов. Данная команда будет выполнена на всех выбранных узлах. Он не будет обрабатываться через оболочку, поэтому такие переменные, как $HOME, и такие операции, как "<", ">", "|" и "&" не будут работать.
Вы можете прочитать больше в разделе Введение в специальные команды.
NB ansible не переключится на следующую группу хостов, пока не будут выполнены все текущие хосты ("вилки"), поэтому его параллелизм ниже, чем у pssh (возможно, есть способ увеличить его, но я этого не знаю),
Файл RemoteMachines выглядит примерно так в обоих случаях:
root@maria-clone1.skynet.tld
root@maria-clone2.skynet.tld
root@maria-clone3.skynet.tld
root@maria-clone4.skynet.tld
Решение для удаленных машин
Перепишите RunJobs.sh примерно так:
find FileDirectory -name 'Input_*' -print0 | xargs -0 -P 2 -n 1 ./Executable
-0, --null
Input items are terminated by a null character instead of by
whitespace, and the quotes and backslash are not special (every
character is taken literally). Disables the end of file string,
which is treated like any other argument. Useful when input items
might contain white space, quote marks, or backslashes. The GNU find
-print0 option produces input suitable for this mode.
-P max-procs, --max-procs=max-procs
Run up to max-procs processes at a time; the default is 1. If
max-procs is 0, xargs will run as many processes as possible at a
time. Use the -n option or the -L option with -P; otherwise chances
are that only one exec will be done.
-n max-args, --max-args=max-args
Use at most max-args arguments per command line. Fewer than
max-args arguments will be used if the size (see the -s option) is
exceeded, unless the -x option is given, in which case xargs will
exit.
nitro2k01, основанное на GNU Parallel, является более мощным, но, как вы можете видеть, GNU xargs тоже не так уж плох.
Во-первых, вы можете посмотреть на использование screen
вместо nohup
для того, чтобы заставить сеанс пережить разъединение. screen
дает вам виртуальный терминал, к которому вы можете вернуться позже. Основное использование screen yourcommand
выполнить yourcommand
а также screen -DR
для автоматического подключения к существующему сеансу или создания нового, если такового не существует. Просто запуск экрана без аргумента также дает вам подсказку внутри "экрана", который вы можете использовать.
Во-вторых, вы можете заглянуть в GNU Parallel для параллельных заданий. Возможно, вы не захотите запускать больше процессов, чем у процессорных ядер, из-за уменьшения отдачи и перегрузки диска. Подходящей командой для вас может быть следующая команда, которая, опять же, вам придется запустить внутри экрана, чтобы он выдержал отключение.
ls FileDirectory/Input_* | parallel -j 8 --workdir $PWD ./Executable {}
Файлы, которые вы хотите обработать, перечислены и переданы в parallel
который получает указание запустить 8 параллельных заданий и работать в текущем каталоге.
Так как screen не понимает каналы и другие вещи в командах, заданных в качестве аргумента - это работа оболочки - вам нужно будет либо поместить команду в сценарий оболочки, либо дать команду sh -c, чтобы выполнить команду.
screen sh -c 'ls FileDirectory/Input_* | parallel -j 8 --workdir $PWD ./Executable {}'
или просто
screen ./runjob
где runjob
содержит:
#!/usr/bin/env bash
ls FileDirectory/Input_* | parallel -j 8 --workdir $PWD ./Executable {}
Используйте экран на каждой машине. screen запускает команду (обычно оболочку), которую можно отсоединить от сеанса ssh, чтобы он продолжал выполнять задание, только что начатое внутри него; другими словами, работа, хотя она все еще выполняется, не будет прервана никаким прерыванием (а не просто kill -9), когда вы выйдете из системы.
Когда вы захотите, вы можете переподключиться через ssh и повторно присоединиться к отдельному сеансу с помощью команды
screen -r
и это без проблем вернет вас в оставленную вами оболочку и покажет вам все стандартные результаты, которые вы пропустили за это время, если таковые имеются.
Таким образом, вам не нужно ничего ждать, и у вас нет опасно зависающих сессий ssh, которые, если случайно отключить, убьют вашу работу.
Экран в репо.
Для меня в {1..9}; do ssh RemoteMachine${i} ./RunJobs.sh; сделанный
попробуй это
for i in {1..9}; do echo RemoteMachine${i}; done |xargs -I % -n 1 -P 10 ssh
% "./RunJobs.sh"
то, что он делает, это создает список имен машин и передает весь список в xargs. Аргументы к xargs означают:
Я заменяю вхождение% первым аргументом
-n 1 использовать 1 аргумент в командной строке
-P 10 запустить 10 процессов одновременно