2016-12-23 126 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" 

但整个过程花费的时间为5秒,而服务器的花费时间为10秒比2秒。这是为什么?无论如何减少时间?我的猜测是exec命令正在等待输出被分配给变量,然后再进入下一个循环?我试图谷歌一点点,但大部分的答案是没有返回任何输出...我需要的输出虽然

+0

start_time = 2016-12-23T17:42:50,end_time = 2016-12-23T17:43:01。大约11秒为5个循环,第一个循环在42:51结束大约1 ++秒 –

回答

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

我不知道如何让你的逻辑更快,但我可以告诉你我用于跟踪有脚本时的运行时间。在脚本的开头部分放置了一些变量$start = date('c');,最后只是简单的echo ' start='.$start; echo ' end='.date(c);

0

是的,你是正确的:你的PHP脚本正在等待每个响应,然后再继续前进。

我认为你希望同时运行所有服务器的请求,而不是等待每个服务器响应。在这种情况下,假设您正在运行线程安全版本的PHP,请查看pthreads。一种选择是使用cURL multi-exec来进行异步请求。那么也有pcntl_fork可以帮助你。另请参阅this & this可能的线程/异步方法的线程。

除此之外,单独测试和基准shell脚本以查看瓶颈的位置,以及是否可以加速它们。这可能比PHP中的线程/异步设置更容易。如果您遇到网络延迟问题,请编写一个执行其他脚本的聚合器shell脚本,并在一个请求中返回结果,并仅在您的PHP脚本中调用该脚本。

+0

我该如何实现cURL multi-exec? –

+0

@LimSY你可以通过cURL向你的服务器发送SSH调用,首先用PHP的'ssh_ *'函数打开一个隧道,然后启动多个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返回所需的数据,并对其进行多重调用。 –