2017-02-20 56 views
0

我正在嘗試使用PHP創建一個網站監控webapp。要監視的網站的URL存儲在MySQL表中。腳本每分鐘通過cron運行 - 循環遍歷所有網站,並使用CURL訪問網站的URL以及CURLINFO_HTTP_CODE獲取HTTP代碼 - 如果網站啓動則返回true,否則返回false。用cron運行Foreach循環的PHP腳本 - 花費太長時間 - 如何更快地執行它

該腳本工作正常 - 有一個或兩個網站運行需要的毫秒數,但有20個網站平均需要運行2-15秒。我可以看到,當添加更多網站時,這會造成問題 - 理想情況下,我需要監控數千個網站,並且用戶能夠添加自己的網站。

我曾經想過當用戶添加一個站點來監視每個URL時添加的個別cron和文件 - 但是我不知道如何去做,並且我可以預見到一些問題,因爲我正在共享服務器。

那麼我應該怎麼做呢,還是有沒有更好的方法,我沒有想到?

<?php 

function visit($url) { 
     // VISITS WEBSITE - RETURNS TRUE IF SITE UP, FALSE IF DOWN 
} 

// GETS THE MONITOR DETAILS FROM DATABASE 
$monitor = new Table($monitorInstance); 
$all_monitors = $monitor->get('monitors'); 
$monitors = $monitor->tableData(); 

//LOOP THROUGH ALL MONITORS 
foreach ($monitors as $monitor1) { 

     $id = $monitor1->id; //GETS ID 
     $website = $monitor1->url; //GETS URL 
     $status = $monitor1->status; //GETS STATUS - 'up' or 'down' 

     // RUNS FUNCTION 
     if (visit($website)) { 
      $new_status = 'up'; 
     } else { 
       $new_status = 'down'; 
     } 

     // IF STATUS CHANGE UPDATE THE DATABASE 
     if ($new_status != $status) { 

       try { 
        //update the database with the new status 
        $monitor->update('monitors', $id, array(
          'status' => $new_status, 
        )); 

       } catch(Exception $e) { //catch exceptions 
        die($e->getMessage()); 
       } 


       // ALSO SEND EMAIL TO USER 


     } 
} 
+2

'它使用CURL訪問網站並獲取HTTP代碼 - 如果網站啓動則返回true,否則返回false爲什麼不捲曲頭並檢查http狀態代碼而不是獲取全部內容這一頁? – JustOnUnderMillions

+0

爲什麼不更新''監視器'與所有新的值,而不是做多個SQL查詢? – JustOnUnderMillions

+1

爲什麼你不看看多捲曲,你可以同時做這些請求 – frz3993

回答

0

並行

PHP運行的請求一般是不平行的任務很大,但它肯定是可能的。簡而言之,HTTP請求是一項非常緩慢的任務 - 服務器和遠程服務器之間有很多來回。 PHP一般設計爲連續 - 這意味着它一次只能做一件事。因此,它最終浪費了大量的時間,等待遠程服務器響應,每次只有一個

  • 關閉發送一個請求
  • 等待年齡
  • 關閉發送一個請求
  • 等待年齡
  • 等!

你想要做的是確保你一起發送很多請求,然後等待它們同時進行。幸運的是,PHP提供了multi curl來做到這一點。

下面是從this great post關於這一主題的示例功能:

<?php 

function multiRequest($data, $options = array()) { 

    // array of curl handles 
    $curly = array(); 
    // data to be returned 
    $result = array(); 

    // multi handle 
    $mh = curl_multi_init(); 

    // loop through $data and create curl handles 
    // then add them to the multi-handle 
    foreach ($data as $id => $d) { 

    $curly[$id] = curl_init(); 

    $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d; 
    curl_setopt($curly[$id], CURLOPT_URL,   $url); 
    curl_setopt($curly[$id], CURLOPT_HEADER,   0); 
    curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1); 

    // post? 
    if (is_array($d)) { 
     if (!empty($d['post'])) { 
     curl_setopt($curly[$id], CURLOPT_POST,  1); 
     curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']); 
     } 
    } 

    // extra options? 
    if (!empty($options)) { 
     curl_setopt_array($curly[$id], $options); 
    } 

    curl_multi_add_handle($mh, $curly[$id]); 
    } 

    // execute the handles 
    $running = null; 
    do { 
    curl_multi_exec($mh, $running); 
    } while($running > 0); 


    // get content and remove handles 
    foreach($curly as $id => $c) { 
    $result[$id] = curl_multi_getcontent($c); 
    curl_multi_remove_handle($mh, $c); 
    } 

    // all done 
    curl_multi_close($mh); 

    return $result; 
} 

?> 

的上述用法是像這樣:

<?php 

// An array of all the URLs to load: 
$data = array(
    'https://..', 
    'https://..', 
    'https://..' 
); 

// Load them now: 
$r = multiRequest($data); 

// r contains an array of responses. 
print_r($r); 

?> 

也有像Parallel Curl太各種庫。

+0

爲了避免崩潰你的initcwnd,你真的應該把你的批量大小(少於20個請求)。並設置請求的時間限制。 – symcbean

+1

謝謝 - 這是一個很大的幫助。 – Ryan