bash параллельное выполнение команд в скрипте
ShParallel
Содержание
Параллельные процессы в Bash/Sh
Ведение
Казалось бы все просто:
Простой пример
и действительно используя код типа :
мы получим работоспособный скрипт.
Усложняем
однако если мы немного усложним скрипт :
Выявление проблемы
убедится в моих словах легко добавив несколько строк отладки :
Решение
Один из вариантов решения проблемы использование только простых внутренних команд bash/sh на участке запуска параллельных процессов:
теперь wait нормально ждет пока все закончат
Сигналы между процессами
Передача сигналов между процессами возможна только от процессов владельцем которых является root или между процессами одного пользователя.
обработка сигналов осуществляется с помощью команды trap задающей функцию обработчик сигнала
что ещё относится к параллельности процессов в bash/sh
Ограничение количества возможных процессов пользователю
с помощью ulimit количество процессов для пользователя может быть ограничено
это не имеет особого смысла если сервер свой и ограниченный круг пользователей вменяем. Однако практически у всех хостинг провайдеров этот параметр ограничен как правило 30-тью процессами. Надо сказать что если вы собираетесь использовать параллельность процессов то подобное ограничение вы быстро почувствуете.
Их (хостинг провайдеров) можно понять если быть в курсе такой строчки :
Ссылки
MNorin.com
Блог про Linux, Bash и другие информационные технологии
Параллельное выполнение в bash
В большинстве командных оболочек команды выполняются по умолчанию последовательно. И это, в принципе, нормально. Потому что человек с системой взаимодействует последовательно, обычно нет необходимости несколько команд выполнять параллельно. Bash в этом смысле тоже не исключение. Но при автоматизации возможность параллельного выполнения может быть полезной. Давайте посмотрим, как организовать параллельное выполнение в bash.
Использование фонового режима
Для организации параллельной работы нескольких программ часто используется запуск в фоновом режиме при помощи знака амперсанда — &. Например:
Команда будет работать в фоне, при этом из текущей оболочки можно выполнять команды. Таким образом уже можно распараллелить какие-то действия. Можно запустить сразу несколько команд таким образом и дождаться, пока они все отработают. Для ожидания запущенных дочерних процессов используется команда wait. Эта команда без параметров ожидает окончания работы всех дочерних процессов, соответственно, для ожидания окончания 5 процессов понадобится выполнить команду всего 1 раз. В принципе, это легко реализуется через цикл. Например, так:
И результат работы этого скрипта:
Как видите, с виду одинаковые команды завершились не в том порядке, в котором мы их запустили. Давайте посмотрим теперь общее время выполнения скрипта.
Общее время работы скрипта чуть больше 10 секунд, что доказывает, что наши команды выполнились параллельно, а увеличение времени выполнения говорит о том, что они были запущены не в одно и то же время, были небольшие таймауты между запусками. Но они были очень маленькими, поэтому такой запуск пяти процессов занимает практически такое же время, как запуск одного.
Использование пайпа
При использовании пайпов, которые перенаправляют вывод одной программы на вход другой, процессы выполняются параллельно. Отсюда вытекает еще один способ параллельного выполнения нескольких команд — перенаправить между ними какие-то данные с помощью пайпа. Например:
Тут важно помнить вот что: если вам не нужно передавать реально какие-то данные между программами, то надо предварительно убедиться, что входные данные эти программы получат в виде опций командной строки и не будут использовать те данные, которые были переданы им с помощью пайпа. Хотя здесь, в принципе, возможен такой вариант:
Этот вариант до использования в скриптах, естественно, нужно обязательно проверить в ручном режиме и посмотреть в страницах руководств используемых программ (если там есть такая информация), что имеет больший приоритет — опции командной строки или стандартный поток ввода, потому что некоторые программы могут игнорировать командную строку, если данные передаются через стандартный поток ввода.
Параллельное выполнение и ограничение количества фоновых задач в скрипте
Давайте рассмотрим такую практическую задачу — запустить 100 процессов параллельно, но так, чтобы работало одновременно не более 10 процессов. В общем, достаточно простая задача. Предположим, что все процессы работают произвольное количество времени. Пусть запуск одной задачи будет выглядеть как запуск команды sleep со случайным параметром от 0 до 29. Тогда скрипт будет выглядеть следующим образом:
Смысл этого скрипта в целом такой: ограничиваем максимально число дочерних фоновых процессов так, чтобы их одновременно было не более 10. Как только один процесс заканчивает свою работу, запускаем следующий. И так далее, пока не выполним 100 фоновых задач. Для порядка отслеживаем в скрипте окончание работы дочерних процессов после запуска последних, только потом заканчиваем работу самого скрипта.
Таким простым способом можно ограничить количество одновременно запущенных фоновых задач в скрипте и при этом отслеживать, сколько из них в данный момент работают. Чтобы было более понятно, запустите скрипт и увидите, когда запускается следующие итерации цикла, и когда изменяется количество дочерних процессов.
Многозадачность в shell-скриптах
Иногда, при написании скрипта на shell хочется выполнять какие-то действия в несколько потоков. Подходящими ситуациями могут быть, например, сжатие большохо количества больших файлов на многопроцессорном хосте и передача файлов по широкому каналу, на котором ограничена скорость индивидуального соединения.
Все примеры написаны на bash, но (с минимальными изменениями) будут работать в ksh. В csh тоже есть средстава управления фоновыми процессами, поэтому подобных подход тоже может быть использован.
JOB CONTROL
Так называется секция в man bash где описаны подробности, на случай если вы любите читать man. Мы используем следующие простые возможности:
command & — запускает команду в фоне
jobs — печатает список фоновых команд
Простой пример, не выполняющий никаких полезных действий. Из файла test.txt читаются числа, и параллельно запускается 3 процесса, которые спят соответствующее количество секунд. Каждые три секунды проверяется число запущенных процессов, и если их меньше трех, запускается новый. Запуск фонового процесса вынесен в отдельную функцию mytask, но можно запускть его непосредственно в цикле.
Обратите внимание на wait после цикла, команда ждет завершения исполняющихся в фоне процессов. Без нее скрипт будет завершен сразу после завершения цикла и все фоновые процессы будут прерваны. Возможно именно этот wait упоминается в известном меме «oh, wait. ».
Завершение фоновых процессов
Эту ситуацию можно обработать, перехватывая нужные сигналы, для чего в начале скрипта добавим обработчик:
Символы групповых операций
Мы уже изучили достаточно команд и наверняка возникал вопрос как применить данные команды сразу к группе файлов. Например, за раз скопировать несколько файлов в каталог или наоборот удалить ненужные файлы. Делать одну и ту же операцию один за другим довольно утомительное и ненужное занятие.
Поэтому в Linux имеются специальные символы, которые позволяют проводить данные операции над несколькими файлами.
Символ “ * ” указывает на любой символ в любом количестве. Поясним на примере.
У нас имеются следующие файлы:
Необходимо скопировать файлы image в каталог photo/. Для этого достаточно выполнить:
Чтобы лучше понять данный принцип рассмотрим возможные применения данного символа в таблице:
Абсолютно все файлы в текущем каталоге
Рассмотрим возможные применения данного символа:
Только с image1.jpg по image9.jpg
cp image1?.jpg photo/
Только с image10.jpg по image15.jpg
В нашем случае выдаст ошибку, так такого файла или каталога не существует
Поясним сказанное на примерах:
cp image[12].jpg photo/
Только файлы image1.jpg и image2.jpg
cp image12.jpg photo/
image1.jpg, image2.jpg, image1.txt, image2.txt
cp image?[13].jpg photo/
Как видно с помощью данных символов можно гибко управлять файлами. Данные символы можно использовать с любыми командами. В последующих разделам мы будем часто с ними встречаться.
Теперь рассмотрим, как можно объединить между собой сразу несколько команд, заставив их выполнять действие последовательно друг за другом либо параллельно.
Последовательное безусловное выполнение
Иногда при выполнении задач в Linux может потребоваться выполнить сразу целую последовательность команд.
Например, нам нужно создать каталог, скопировать группу файлов student*.jpg в данный каталог и проверить размер данного каталога в килобайтах.
Для этого мы выполним следующее:
cp student*.jpg photo/
Пришлось последовательно вводить команду, затем ждать ее завершения и вводить следующую. Однако данный процесс можно оптимизировать, введя все команды одну за другой, отделив каждую точкой с запятой:
Результат будет тот же, но в данном случае мы все сделали гораздо быстрее. Это особенно актуально, если приходится использовать команды, на выполнение которых может уходить больше времени.
Следует помнить, что выполнение всегда передается следующей команде даже, если выполнение предыдущей команды завершилось с ошибкой.
Последовательное выполнение при соблюдении условия
Может возникнуть ситуация, когда от успешного выполнения первых команд зависит выполнение последующих команд. То есть, если первая команда завершилась с ошибкой, то вторую команду выполнять не будем.
Например, из каталога photo/ нам нужно скопировать файлы на внешний носитель, а затем удалить их из каталога photo/. В принципе можно воспользоваться указанной ниже последовательностью
cp student*.jpg /media/StudentFlash; rm student*.jpg
Чтобы избежать подобных ситуаций можно воспользоваться конструкцией:
cp student*.jpg /media/StudentFlash && rm student*.jpg
Следующий символ объединения » || « используется, когда из 2-х (или более) команд нужно выполнить либо первую либо вторую команду. То есть, если первая команда завершилась с ошибкой, то ход переходит следующей команде, а если первая команда все же успешно завершилась, то вторая команда выполняться не будет.
cd music/ || mkdir music
Передача выхода одной команды на вход другой команды
Иногда при работе с командой ls выводится слишком много информации, которая не помещается на всем экране и приходится прокручивать текст, чтобы увидеть начало
Теперь попробуем в системе найти файл под названием icon с помощью команды locate (рассмотрим подробнее позже):
Система может выдать сотни и тысячи значений. Здесь тоже можем воспользоваться символом » | «:
locate * icon | less
Конечно можно. Для этого существует другой символ объединения команд » > « :
locate * icon > search_result.txt
А файл search_result.txt нужно предварительно создавать?
Нет, если его нет, то система создаст его автоматически. А если он есть, то система перезапишет все его содержимое.
То есть мы можем все потерять по неосторожности?
Совершенно верно, но есть 2 способа избежать этого.
1-й способ. Можно установить специальную опцию noclobber :
Теперь, если файл существует, то система выдаст следующее сообщение:
Чтобы отключить эту опцию выполни
Подстановка вывода одной команды под аргумент второй команды
Некоторые команды не могут использоваться самостоятельно без указания аргументов. В качестве аргументов обычно выступают файлы, каталоги либо различные шаблоны и условия (об этом немного позже).
Вместо аргументов в некоторых случаях можно использовать и результаты выполнения некоторых команд.
Это простая текстовая строка. Попробуем подставить данную строку, чтобы создать каталоги согласно указанной строке. Для этого можно воспользоваться конструкцией типа $() :
Данная последовательность создает каталог по текущей дате.
4 инструмента для одновременного выполнения команд на нескольких Linux-серверах
Статья, перевод которой мы сегодня публикуем, посвящена технологиям одновременного выполнения команд на нескольких Linux-серверах. Речь здесь пойдёт о нескольких широко известных инструментах, реализующих подобный функционал. Этот материал пригодится системным администраторам, которым, например, регулярно приходится проверять состояние множества удалённых систем. Предполагается, что у читателя уже имеется несколько серверов, к которым организован доступ по SSH. Кроме того, при одновременной работе с несколькими машинами весьма полезно настроить SSH-доступ к ним по ключу, без пароля. Такой подход, с одной стороны, повышает безопасность сервера, а с другой — облегчает работу с ним.
1. PSSH — Parallel SSH
Затем parallel-ssh устанавливают с использованием pip :
Далее, нужно внести имена хостов или IP-адреса удалённых Linux-серверов и сведения о портах в файл hosts (на самом деле, назвать его можно как угодно). Тут нам пригодится такая команда:
Вот пример содержимого такого файла:
Команда запуска parallel-ssh может выглядеть так:
На следующем рисунке показано использование утилиты при работе с тремя серверами.
Утилита parallel-ssh выполняет команды на нескольких серверах
2. Pdsh — Parallel Remote Shell Utility
Pdsh — это, опять же, опенсорсное решение, представляющее собой оболочку для одновременного выполнения команд на нескольких Linux-серверах.
Вот как установить pdsh в различных дистрибутивах:
Вот как выглядит работа с этой командой.
Выполнение команд на нескольких серверах с использованием pdsh
3. ClusterSSH
Теперь, для подключения к серверам, нужно выполнить команду следующего вида:
Можно воспользоваться и такой конструкцией:
После этого вы увидите нечто, подобное тому, что показано на следующем рисунке.
Работа с несколькими серверами с помощью clusterssh
Команды, введённые в консоли администратора, выполняются на всех серверах. Для выполнения команд на отдельном сервере нужно вводить их в окне, открытом для него.
4. Ansible
Ansible — это популярный опенсорсный инструмент для автоматизации IT-процессов. Он используется для настройки систем и для управления ими, для установки приложений и для решения других задач.
Вот пример фрагмента подобного файла с несколькими системами, объединёнными в группу webservers :
Обратите внимание на то, что интерфейс командной строки ansible позволяет выполнять команды лишь по одной.
Взаимодействие с несколькими серверами средствами ansible
Итоги
В этом материале мы рассказали об инструментах, которые предназначены для одновременного выполнения команд на нескольких серверах, работающих под управлением Linux. Если вы подумываете об автоматизации задач по управлению множеством серверов — надеемся, вы найдёте здесь что-нибудь такое, что вам подойдёт.
Уважаемые читатели! Знаете ли вы о каких-нибудь полезных утилитах, упрощающих администрирование большого количества серверов?