2017-02-20 16 views
0

Я пытаюсь создать веб-сайт мониторинга webapp с PHP. URL-адреса сайтов для мониторинга хранятся в таблице MySQL. Скрипт запускается каждую минуту через cron - он проходит через все веб-сайты и URL-адрес foreach, он использует CURL для посещения сайта и CURLINFO_HTTP_CODE, чтобы получить код HTTP - он возвращает true, если сайт вверх и false, если нет.PHP-скрипт с циклом Foreach, работающий с cron - занимает слишком много времени - как это сделать быстрее

Сценарий работает нормально - с одним или двумя веб-сайтами он запускает миллисекунды, но с 20 сайтами он занимает в среднем 2-15 секунд для запуска. Я вижу, что это вызовет проблемы при добавлении большего количества сайтов - в идеале мне нужно отслеживать тысячи сайтов и пользователей, чтобы они могли добавлять свои собственные сайты.

Я подумал о том, что отдельные клоны и файлы добавляются для каждого URL-адреса, когда пользователь добавляет сайт для мониторинга - однако я не уверен, как это сделать, и я могу предвидеть некоторые проблемы, поскольку я работаю над общим сервер.

Так как же я должен идти об этом или есть лучший способ, о котором я не думал?

<?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-status вместо того, чтобы получать полный контент страница? – 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 запросов). И установите timelimit на запросы. – symcbean

+1

Спасибо - это отличная помощь. – Ryan