Удаленная очередь задач с использованием bash & ssh для переменного числа живых работников

Я хочу распределить работу с главного сервера на несколько рабочих серверов с помощью пакетов.

В идеале у меня был бы tasks.txt файл со списком задач для выполнения

cmd args 1
cmd args 2
cmd args 3
cmd args 4
cmd args 5
cmd args 6
cmd args 7
...
cmd args n

и каждый рабочий сервер будет подключаться с помощью ssh, читать файл и отмечать каждую строку как в процессе или сделано

#cmd args 1  #worker1 - done
#cmd args 2  #worker2 - in progress
#cmd args 3  #worker3 - in progress
#cmd args 4  #worker1 - in progress 
cmd args 5
cmd args 6
cmd args 7
...
cmd args n

Я знаю, как сделать ssh-соединение, прочитать файл и выполнить удаленно, но не знаю, как сделать чтение и запись атомной операции, в чтобы не было случаев, когда 2 сервера запускают одну и ту же задачу, и как обновить строку.

Я хотел бы, чтобы каждый работник переходил к списку задач и блокировал следующую доступную задачу в списке, а не сервер, активно командующий рабочими, поскольку у меня будет гибкое количество рабочих клонов, которые я начну или закрою в зависимости от того, как быстро мне понадобятся задачи для завершения.

обновление:

и моя ideea для рабочего скрипта будет :

#!/bin/bash

taskCmd=""
taskLine=0
masterSSH="ssh usr@masterhost"
tasksFile="/path/to/tasks.txt"

function getTask(){
    while [[ $taskCmd == "" ]]
    do
        sleep 1;
        taskCmd_and_taskLine=$($masterSSH "#read_and_lock_next_available_line $tasksFile;")
        taskCmd=${taskCmd_and_taskLine[0]}
        taskLine=${taskCmd_and_taskLine[1]}
    done
}

function updateTask(){
    message=
    $masterSSH "#update_currentTask $tasksFile $taskLine $message;"
}


function doTask(){
    return $taskCmd;
}


while [[ 1 -eq 1 ]]
do 
    getTask
    updateTask "in progress"
    doTask 
    taskErrCode=$?
    if [[ $taskErrCode -eq 0 ]]
    then 
        updateTask "done, finished successfully"
    else
        updateTask "done, error $taskErrCode"
    fi
    taskCmd="";
    taskLine=0;

done

3 ответов


можно использовать flock для одновременного доступа к файлу:

exec 200>>/some/any/file ## create a file descriptor
flock -w 30 200 ## concurrently access /some/any/file, timeout of 30 sec.

вы можете указать дескриптор файла в список задач или любой другой файл, но, конечно же, тот же файл, чтобы flock работа. Замок я снял, как только что это сделал или плохо. Вы также можете удалить замок самостоятельно, когда он вам больше не нужен:

flock -u 200

пример использования:

ssh user@x.x.x.x '
  set -e
  exec 200>>f
  echo locking...
  flock -w 10 200
  echo working...
  sleep 5
'

set -e сбой сценария при сбое любого шага. Играть с the sleep time и выполнить этот скрипт параллельно. Только один sleep будет выполняться одновременно.


попробуйте реализовать что-то вроде

while read line; do    
   echo $line  
   #check if the line contains the # char, if not execute the ssh, else nothing to do
   checkAlreadyDone=$(grep "^#" $line)
   if [ -z "${checkAlreadyDone}" ];then
      <insert here the command to execute ssh call>
      <here, if everything has been executed without issue, you should 
      add a commad to update the file taskList.txt
      one option could be to insert a sed command but it should be tested>
   else
      echo "nothing to do for $line" 
   fi
done < taskList.txt

С уважением Клаудио!--2-->


Проверьте, изобретаете ли вы GNU Parallel:

parallel -S worker1 -S worker2 command ::: arg1 arg2 arg3

GNU Parallel является общим параллелизатором и позволяет легко запускать задания параллельно на одной машине или на нескольких машинах, к которым у вас есть доступ ssh. Он часто может заменить for петли.

Если у вас есть 32 разных задания, которые вы хотите запустить на 4 процессорах, прямой способ распараллеливания-запустить 8 заданий на каждом процессоре:

Simple scheduling

GNU Parallel вместо этого порождает новый процесс когда один заканчивает-сохраняя процессоры активными и, таким образом, экономя время:

GNU Parallel scheduling

установка

Если GNU Parallel не упакован для вашего дистрибутива, вы можете выполнить личную установку, которая не требует корневого доступа. Это можно сделать за 10 секунд, сделав следующее:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

для других вариантов установки см. http://git.savannah.gnu.org/cgit/parallel.git/tree/README

узнать больше

см. дополнительные примеры:http://www.gnu.org/software/parallel/man.html

смотрите вступление видео:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

пройдите через учебник:http://www.gnu.org/software/parallel/parallel_tutorial.html

подпишитесь на список электронной почты, чтобы получить поддержку:https://lists.gnu.org/mailman/listinfo/parallel