원격 명령의 병렬 실행

원격 명령의 병렬 실행

설정:

Linux 서버 목록이 포함된 파일을 처리한 다음 다음과 같이 ssh를 통해 해당 원격 서버에서 bash 또는 perl 스크립트를 실행하는 PHP 스크립트(현재 PHP5.5용으로 작성되었지만 실행 중인 서버에는 7.4가 있음)가 있습니다.

exec("ssh -o StrictHostKeyChecking=no -p $connectivity_port $user@$server \"bash -s\" -- < $file $scriptargs 2>&1", $result, $exit_code);

이 모든 작업은 잘 작동하지만 실행되는 코드에 따라 시간이 걸립니다. 로컬이기 때문에 스크립트 출력 외에는 처리할 것이 거의 없습니다(PHP를 실행하는 서버의 로컬 파일에 대한 로깅과 일부 스크립트 출력이 많이 있습니다).

표적

bash에서 병렬로 PHP 스크립트를 실행하는 가장 좋은/가장 쉬운 방법/도구가 무엇인지 궁금합니다. 모든 출력이 목록에 있는 서버의 순서대로 있는지 확인하세요(예: 한 번에 x개 서버, 아마도 10개, 실행 시간 단축)

내 연구와 버전 제약으로 볼 때 PHP 자체는 갈 길이 아닌 것 같고 bash는 그 계산서에 맞지 않는 것 같지만 나는 기꺼이 틀릴 수 있고 다른 방법을 배울 의향이 있습니다.

답변1

당신은 다음과 같은 일을 할 것 입니다 bash:

declare -r MAX_PARALLEL='5' WAITSEC='0.1'

i=0
server[i]=...
port[i]=...
user[i]=...
command_file[i]=...
scriptargs[i]=...
((i++))
server[i]=...
port[i]=...
user[i]=...
command_file[i]=...
scriptargs[i]=...
((i++))

count=$i
for((i=0;i<count;i++)); do
    while [ $(jobs -r | wc -l) -gt "$MAX_PARALLEL" ]; do
        sleep "$WAITSEC"
    done
    ( ssh -o StrictHostKeyChecking=no -p "${port[i]}" "${user[i]}@${server[i]}" \
"bash -s" <"${file[i]}" "${scriptargs[i]}" >output_file.$i 2>&1
      echo $? >exit_code.$i ) &
done

불행하게도 올바른 작업 수를 얻는 쉬운 방법은 없는 것 같습니다. 따라서 이 방법은 명령줄에 개행 문자가 포함되어 있지 않은 경우에만 올바르게 작동합니다.

답변2

Synology DS218에서 비슷한 것을 실행했습니다.

제 경우에는 PHP 스크립트가 다양한 명령어를 사용하여 bash 스크립트를 준비한 후 스크립트를 실행합니다.

이것은 다음과 같이 작동합니다.내 거사례

  • 모든 서버는 분리되어 있습니다. (서버에 과부하가 걸리지 않습니다.)
  • 서버 12의 오류는 12 이후 서버를 중지하고 건너뛰는 것을 의미하지 않습니다.

이러한 요구 사항이 충족되지 않으면 다른 작업을 수행해야 합니다.

하지만 그들이 있는 한,

#!/bin/bash

ssh server1 "command1" > output1 2> error1 &
ssh server2 "command2" > output2 2> error2 &
...
ssh serverN "commandN" > outputN 2> errorN &
# wait for all SSHs to complete
wait

마지막으로 모든 출력 파일은 번호순으로 수집되어 삭제됩니다.

답변3

펄을 사용할 수 있습니다병렬::ForkManager그리고IPC::오픈2.

용법:

cat list_of_servers.txt | perl para.pl /path/to/script.sh ARG1 ARG2

코드 para.pl:

#!/usr/bin/env perl
use v5.20;
use IPC::Open2 qw(open2);
use Parallel::ForkManager qw();
sub run_script_on_server {
    my ( $server, $script, @args ) = @_;
    say "$$ running script: $script on server: $server with args: @args";
    # TODO: replace with ssh invocation
    my $pid = open2( my $chld_out, my $chld_in, "bash", $script, @args );
    local $/ = undef;
    return <$chld_out>;
}
my $pm = Parallel::ForkManager->new(10);    
while ( my $server = <STDIN> ) {
    $pm->start and next;
    chomp $server;
    my $result = run_script_on_server( $server, @ARGV );
    say "$$ result from $server: $result";
    $pm->finish;
}

답변4

이를 수행하는 두 가지 방법을 제안할 수 있습니다.

매개변수

줄 바꿈으로 구분된 호스트 이름 목록이 포함된 파일이 있고 사용하는 모든 연결 user에 대해 .portxargs

xargs -I '{}' -P <max-procs> --arg-file <INPUTFILE> bash -c "ssh -o StrictHostKeyChecking=no -p $connectivity_port $user@{} 'bash -s' < $file $scriptargs > $OUT_FOLDER/{}.log 2>&1"

or

cat <INPUTFILE> | xargs -I '{}' -P <max-procs> bash -c "ssh -o StrictHostKeyChecking=no -p $connectivity_port $user@{} 'bash -s' < $file $scriptargs > $OUT_FOLDER/{}.log 2>&1"

이 플래그를 사용하여 동시성을 설정할 수 있습니다 -P.

       --max-procs=max-procs
       -P 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 with -P; otherwise chances  are  that
              only one exec will be done.

각 명령의 출력을 기록합니다 $OUT_FOLDER/$HOST.log.

user서로 다른 기계 가 있고 port각 기계에 대해 계속 사용할 수 있지만 xargs조금 더 복잡해집니다.

PDSH

또 다른 옵션은 다음을 사용하는 것입니다.pdsh"병렬로 호스트 그룹에 명령을 실행할 수 있습니다."

pdsh -R exec -w^<INPUT FILE> -f <max-procs> bash -c "ssh -o StrictHostKeyChecking=no -p $connectivity_port %u@%h 'bash -s' < $file $scriptargs 2>&1"

이는 xargs 의 플래그와 유사합니다 -f.-P

exec    Executes an arbitrary command for each target host. The first of the pdsh remote arguments is the local command
        to execute, followed by any further arguments. Some simple parameters  are  substitued  on  the  command  line,
        including  %h  for  the target hostname, %u for the remote username, and %n for the remote rank [0-n] (To get a
        literal % use %%).  For example, the following would duplicate using the ssh module to run  hostname(1)  across
        the hosts foo[0-10]:

          pdsh -R exec -w foo[0-10] ssh -x -l %u %h hostname

       and this command line would run grep(1) in parallel across the files console.foo[0-10]:

          pdsh -R exec -w foo[0-10] grep BUG console.%h

-f number
       Set the maximum number of simultaneous remote commands to number.  The default is 32.

접두사가 붙은 명령의 출력을 덤프하는 경우HOSTNAME:

여기에 예가 있습니다.

$ pdsh -R exec -w host1,host2 bash -c "ssh  -o StrictHostKeyChecking=no -p 22 %u@%h 'bash -s' <<< 'echo Running script on %h with arguments: \${@}' arg1 arg2 arg3"
host1: Running script on host1 with arguments: arg1 arg2 arg3
host2: Running script on host2 with arguments: arg1 arg2 arg3

관련 정보