2016-12-23 145 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返回所需的數據,並對其進行多重調用。 –