Дикая нагрузка на сервер (CPU) от функции multi curl

Статус
В этой теме нельзя размещать новые ответы.

SocMaster

Профессор
Регистрация
26 Июл 2011
Сообщения
211
Реакции
49
PHP:
function bingcontent($key) {
    global $_lang;

    if (mb_detect_encoding($key) == "UTF-8"):
        $key = trim($key);
    else:
        $key = iconv(mb_detect_encoding($key) , "UTF-8", $key);
        $key = trim($key);
    endif;

    $key = urlencode($key);

    //$key = preg_replace(array("/ /","/_/","/-/"), "+", $key);

    $newcontent = array();
  
    for ($_i = 0; $_i <= 10; $_i++){
        $urlsbing[] = "http://www.bing.com/search?q=" . $key . "&qs=n&form=QBLH&pq=viagra&first=" . $_i . "1&setmkt=" . $_lang . "&setlang=" . $_lang . "&setplang=" . $_lang;
    }
    $_pattern = "|<\/span><\/div><p>(.*)<\/p><\/div|iU";
    $_pattern_content = array(" ...","...","....","..","!.","?.");
    $curldatabing = curlMultiRequest($urlsbing);
    foreach($curldatabing as $value){
        $_response = str_replace("\n", " ", $value);

        preg_match_all($_pattern, $_response, $_matches);

        if (!empty($_matches)){
            $_content = implode(". ", $_matches[1]);
            $_content = str_replace($_pattern_content, ". ", $_content);
            $newcontent[] = $_content . ". ";
        }
    }
 
    $newcontent = implode($newcontent);

    $newcontent = strip_tags($newcontent);
    if (mb_detect_encoding($newcontent) == "UTF-8"):
        $newcontent = trim($newcontent);
    else:
        $newcontent = iconv(mb_detect_encoding($newcontent) , "UTF-8", $newcontent);
        $newcontent = trim($newcontent);
    endif;

    return $newcontent;

}
Есть вот такая функция парсинга текста из бинга, нагрузка часто поднимается до 100% на цп
Запросов много на эту функцию ежесекундно, что можно придумать что б уменьшит нагрузку?
 
cURL заменить на file_get_contents
 
cURL заменить на file_get_contents
В функции стоит мультикурл, есть что то подобное для file_get_contents?
Если поставить в цикл file_get_contents тучу времени займут эти запросы, мультикурл намного быстрее, тестировал
Может тут баг какой оставил
PHP:
function curlMultiRequest($urls, $options = array()) {
        $ch = array();
        $results = array();
        $cmh = curl_multi_init();
        foreach($urls as $key => $val) {
            $ch[$key] = curl_init();
            if ($options) {
                curl_setopt_array($ch[$key], $options);
            }
            curl_setopt($ch[$key], CURLOPT_URL, $val);
            //curl_setopt($ch[$key], CURLOPT_HEADER, true);
            curl_setopt($ch[$key], CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch[$key], CURLOPT_CONNECTTIMEOUT, 10);
            curl_setopt($ch[$key], CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/600.5.17 (KHTML, like Gecko) Version/8.0.5 Safari/600.5.17");
            curl_setopt($ch[$key], CURLOPT_REFERER, $val);
            $tasks[$val] = $ch[$key];
            curl_multi_add_handle($cmh, $ch[$key]);
        }
        $active = null;
        do {
            $mrc = curl_multi_exec($cmh, $active);
        }
        while ($mrc == CURLM_CALL_MULTI_PERFORM );
      
        while ($active && ($mrc == CURLM_OK)) {
            // если какой-либо поток готов к действиям
            if (curl_multi_select($cmh) != -1) {
                // ждем, пока что-нибудь изменится
                do {
                    $mrc = curl_multi_exec($cmh, $active);
                    // получаем информацию о потоке
                    $info = curl_multi_info_read($cmh);
                    // если поток завершился
                    if ($info['msg'] == CURLMSG_DONE) {
                        $ch = $info['handle'];
                        // ищем урл страницы по дескриптору потока в массиве заданий
                        $url = array_search($ch, $tasks);
                        // забираем содержимое
                        $tasks[$url] = curl_multi_getcontent($ch);
                        // удаляем поток из мультикурла
                        curl_multi_remove_handle($cmh, $ch);
                        // закрываем отдельное соединение (поток)
                        curl_close($ch);
                    }
                }
                while ($mrc == CURLM_CALL_MULTI_PERFORM);
            }
        }
      
        return $tasks;
    }
Может есть доп модули для сервера что б как то ускорить запросы, стоит nginx + php-fpm
 
Выбирайте между скоростью и нагрузкой на процессор.
Да и какие вообще характеристики сервера? Небось на шаред хостинге лимита достигли?
А контент от бинга за какое время получаете?
Попробуйте запустить ваш скрипт на локалке с какой нибудь мощной конфигурацией компьютера.
 
Нет, выделенный сервер, Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz 2668.000 Mhz X 8 оперативки в пределах 50 гигов
Стоит nginx + php-fpm
По нагрузке качели
e9e2b-clip-30kb.png

в php-fpm slow logs указывают на эту функцию парсинга текста
Скрипт когда все идеально, время загрузки до 1сек это функция из доргена одного. вот на неё и указывает сервер что виснет со временем
 
Нет, выделенный сервер, Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz 2668.000 Mhz X 8 оперативки в пределах 50 гигов
Стоит nginx + php-fpm
По нагрузке качели
e9e2b-clip-30kb.png

в php-fpm slow logs указывают на эту функцию парсинга текста
Скрипт когда все идеально, время загрузки до 1сек это функция из доргена одного. вот на неё и указывает сервер что виснет со временем
Обязательно отрабатывать моментально? Может слипы проставить, а результат выполнения скрипта всё равно будет, не важно на сколько быстро.
 
Обязательно отрабатывать моментально? Может слипы проставить, а результат выполнения скрипта всё равно будет, не важно на сколько быстро.
Началось все с того, что сервер просто падал на время из-за нагрузки, глянул, там в цикле file_get_contents
поставил мультикурл, время с 5-8 сек упало до 1-2
сервер начал жить дольше намного. но что то со временим подвисает с нагрузкой

А куда слипы поставить?
 
Последнее редактирование модератором:
Проанализируйте, в каком цикле у вас самая ресурсоемкая задача, там и ставьте sleep. Я не уверен, что поможет, но попробуйте. Будет интересно глянуть на ваш график.
Код:
foreach($curldatabing as $value){
        usleep(500000); //пол секунды
        $_response = str_replace("\n", " ", $value);

        preg_match_all($_pattern, $_response, $_matches);

        if (!empty($_matches)){
            $_content = implode(". ", $_matches[1]);
            $_content = str_replace($_pattern_content, ". ", $_content);
            $newcontent[] = $_content . ". ";
        }
    }
И на боевом сервере уберите везде комментарии. Это конечно экономия на спичках...
 
PHP:
        // если какой-либо поток готов к действиям      
        if (curl_multi_select($cmh) !== -1) {     
            do {
                $mrc = curl_multi_exec($cmh, $active);
                // получаем информацию о потоке
                $info = curl_multi_info_read($cmh);
                // если поток завершился
                if ($info['msg'] == CURLMSG_DONE) {
                    $ch = $info['handle'];
                    // ищем урл страницы по дескриптору потока в массиве заданий
                    $url = array_search($ch, $tasks);
                    // забираем содержимое
                    $tasks[$url] = curl_multi_getcontent($ch);
                    // удаляем поток из мультикурла
                    curl_multi_remove_handle($cmh, $ch);
                    // закрываем отдельное соединение (поток)
                    curl_close($ch);
                }
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        } else {
            usleep(100);
        }
Попробуйте подобрать оптимальное значение для usleep(100);
 
cURL заменить на file_get_contents
Плохой совет:
2015-09-07_22-13_php_multicurl_vs_fgc.jpg
Проводил несколько замеров, multicurl в 2-2,5 раза быстрее file_get_contents

Проанализируйте, в каком цикле у вас самая ресурсоемкая задача, там и ставьте sleep. Я не уверен, что поможет, но попробуйте. Будет интересно глянуть на ваш график.
PHP:
foreach($curldatabing as $value){
        usleep(500000); //пол секунды
И на боевом сервере уберите везде комментарии. Это конечно экономия на спичках...
Совет правильный, а вот место для usleep плохое - весь этот цикл меньше 0,01 секунды выполняется

PHP:
else {
            usleep(100);
        }
Попробуйте подобрать оптимальное значение для usleep(100);
А вот это хороший совет, только время надо от 100000 перебирать с шагом 50000.
Прикол в том, что даже на самом быстром сервере для соединения с сайтом и загрузки контента нужны сотни мс и за это время while цикл успевает вызвать функции curl_multi_select, curl_multi_exec, curl_multi_info_read в значительно большее количество раз, чем это необходимо, а функции грузят проц. Вот скрин без usleep или со слишком маленьким значением:

2015-09-07_22-45.jpg

Вот скрин с usleep(100000) :
2015-09-07_22-48.jpg

68/14 = 5 примерно в 5 раз меньше будет нагрузка на проц.
В идеале было бы чтобы эти функции вызывалась, ровно столько раз, сколько ссылок мы загружаем, достигается это большими значениями в usleep, но в таком случае это может значительно увеличить время выполнения скрипта, хотя нагрузка на проц будет оптимальной.

PS: количество вызовов и название функций может отличаться (я код немного адаптировал под win), но суть не меняется...
 
Последнее редактирование:
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху