2016-12-23 3 views
5

У меня есть массив с сервером объекта так:PHP работает несколько сценариев одновременно

Array 
(
    [0](
       (
        [id] => 1 
        [version] => 1 
        [server_addr] => 192.168.5.210 
        [server_name] => server1 
       ) 
     ) 
    [1](
       (
        [id] => 2 
        [server_addr] => 192.168.5.211 
        [server_name] => server2 
       ) 
     ) 
) 

Запустив код, приведенный ниже, я смог получить желаемый результат

foreach ($model as $server) { 
     $cpu_usage = shell_exec('sudo path/to/total_cpu_usage.sh '.$server->server_addr); 
     $memory_usage = shell_exec('sudo path/to/total_memory_usage.sh '.$server->server_addr); 
     $disk_space = shell_exec('sudo path/to/disk_space.sh '.$server->server_addr); 
     $inode_space = shell_exec('sudo path/to/inode_space.sh '.$server->server_addr); 
     $network = shell_exec('sudo path/to/network.sh '.$server->server_addr); 
     exec('sudo path/to/process.sh '.$server->server_addr, $processString); 
     $processArray = array(); 
     foreach ($processString as $i) { 
      $row = explode(" ", preg_replace('/\s+/', ' ', $i)); 
      array_push($processArray,$row); 
     } 
     $datetime = shell_exec('sudo path/to/datetime.sh '.$server->server_addr); 
     echo $cpu_usage; 
     echo $mem_usage; 
     echo $disk_space; 
     ...... 
} 

Мои скрипты похожие на:

#!/bin/bash 
if [ "$1" == "" ] 
then 
     echo "To start monitor, please provide the server ip:" 
     read IP 
else 
     IP=$1 
fi 

ssh [email protected]$IP "date" 

Но весь процесс занял 10 секунд для 5 серверов по сравнению с 1 сервером за меньшие чем 2 сек. Почему это? В любом случае, чтобы уменьшить время? Я предполагаю, что команда exec ожидала, что выход будет назначен переменной перед переходом к следующему циклу? Я пытался немного поработать с Google, но большая часть ответа для этого не требуется, так как я не возвращаю никакого вывода ... Мне нужен вывод, хотя

+0

start_time = 2016-12-23T17: 42: 50, end_time = 2016-12-23T17: 43: 01. около 11 секунд для 5 циклов, первый конец цикла в 42:51, примерно 1 ++ sec –

ответ

6

Вы можете запускать свои скрипты одновременно с popen() и затем получать выход с помощью fread().

//execute 
foreach ($model as $server) { 
    $server->handles = [ 
     popen('sudo path/to/total_cpu_usage.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/total_memory_usage.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/disk_space.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/inode_space.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/network.sh '.$server->server_addr, 'r'), 
    ]; 
} 

//grab and store the output, then close the handles 
foreach ($model as $server) { 
    $server->cpu_usage = fread($server->handles[0], 4096); 
    $server->mem_usage = fread($server->handles[1], 4096); 
    $server->disk_space = fread($server->handles[2], 4096); 
    $server->inode_space = fread($server->handles[3], 4096); 
    $server->network = fread($server->handles[4], 4096); 

    foreach($server->handles as $h) pclose($h); 
} 

//print everything 
print_r($model); 

Я испытал подобный код, чтобы выполнить 5 сценариев, которые спят в течение 2 секунд, и все это заняло всего 2,12 секунды вместо 10,49 секунд shell_exec().

Обновление 1: Большое спасибо Markus AO за то, что указали на потенциал оптимизации.

Обновление 2: Изменен для удаления возможности перезаписи. Результаты теперь находятся внутри $model.

Это может также показать, какой сервер отказался от соединения, если проблема с sshd влияет на вас.

+0

Я понимаю, что он все еще не работает одновременно. но это немного быстрее –

+0

Это простой и простой подход. Возможно, вы сможете ускорить его, если разделите его на две петли, первый из которых просто откроет все дескрипторы (например, как '$ handles [$ server]'), которые делают вызовы запущенными на фоне, а второй один читает все ответы и закрывает ручки. Именно поэтому мы получаем все запросы хруст, прежде чем ожидать (и, возможно, ждать) чего-либо. Я думаю, это будет достаточно одновременным! –

+0

хорошо я попробую, когда я доберусь до офиса, спасибо за помощь –

0

Я не знаю, как сделать вашу логику быстрее, но я могу рассказать вам, как я использовать для отслеживания времени работы, когда у меня есть сценарии. В начале скрипта поместите несколько var $start = date('c'); и в конце просто прост echo ' start='.$start; echo ' end='.date(c);

0

Да, вы правы: ваш PHP-скрипт ждет каждого ответа, прежде чем двигаться дальше.

Предполагаю, что вы надеетесь запускать запросы на все серверы одновременно, вместо того, чтобы ждать ответа каждого сервера. В этом случае, если вы используете поточно-безопасную версию PHP, посмотрите на pthreads. Один из вариантов - использовать cURL multi-exec для создания асинхронных запросов. Тогда есть также pcntl_fork, которые могут вам помочь. Также см. this & this нить для возможных потоков/асинхронных подходов.

Помимо этого, выполните проверку и проверку сценариев оболочки в отдельности, чтобы узнать, где находятся узкие места, и можете ли вы ускорить их. Это может быть проще, чем потоки/асинхронные настройки в PHP. Если у вас возникли проблемы с сетевой задержкой, напишите сценарий оболочки агрегатора, который выполняет другие скрипты и возвращает результаты в одном запросе, и вызывается только в вашем скрипте PHP.

+0

Как реализовать cURL multi-exec? –

+0

@ LimSY вы должны сделать SSH вызовы cURL на ваш сервер (ы), сначала открыв туннель с функциями 'ssh_ *' PHP, а затем запустив multi-cURL и добавив каждый запрос в качестве дескриптора. Основы cURL multi init/exec находятся здесь: http://php.net/manual/en/function.curl-multi-init.php и http://php.net/manual/en/function.curl-multi -exec.php ... и пример использования SSH здесь: http://stackoverflow.com/questions/22765956/php-ssh2-tunnel-using-proxy-socks-throw-ssh-server ... это (довольно сложное) подход к параллельным вызовам будет иметь смысл, если вы напрямую подключаетесь к удаленным серверам. –

+0

И к этому я должен добавить, что я не играл с самим компилятором cURL/SSH, и, похоже, не так много информации в Интернете. Если вы спуститесь по этому маршруту, приготовьтесь к хорошему взлому. Другой вариант для cURL, возможно, более простой способ - создать базовый API, который возвращает требуемые данные через HTTP, и вместо этого сделает несколько вызовов. –

0

Все, что вам нужно сделать, это добавить > /dev/null & в конец Linux, вы не получите результат, хотя он будет работать как фоновый (асинхронный) процесс.

shell_exec('sudo path/to/datetime.sh '.$server->server_addr.' > /dev/null &'); 

смотри также этот сценарий Фоновый процесс от моего GitHub, (имеет окна совместимые фоновые процессы)

https://github.com/ArtisticPhoenix/MISC/blob/master/BgProcess.php

Ура!

Смежные вопросы