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

Тема в разделе "PHP", создана пользователем SocMaster, 6 сен 2015.

Статус темы:
Закрыта.
Модераторы: latteo
  1. SocMaster

    SocMaster aka Hakerok

    Регистр.:
    26 июл 2011
    Сообщения:
    202
    Симпатии:
    47
    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% на цп
    Запросов много на эту функцию ежесекундно, что можно придумать что б уменьшит нагрузку?
     
  2. PirateGod

    PirateGod Постоялец

    Регистр.:
    6 июн 2014
    Сообщения:
    80
    Симпатии:
    72
    cURL заменить на file_get_contents
     
  3. SocMaster

    SocMaster aka Hakerok

    Регистр.:
    26 июл 2011
    Сообщения:
    202
    Симпатии:
    47
    В функции стоит мультикурл, есть что то подобное для 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_RETURNTRANSFERtrue);
                
    curl_setopt($ch[$key], CURLOPT_CONNECTTIMEOUT10);
                
    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
     
  4. PirateGod

    PirateGod Постоялец

    Регистр.:
    6 июн 2014
    Сообщения:
    80
    Симпатии:
    72
    Выбирайте между скоростью и нагрузкой на процессор.
    Да и какие вообще характеристики сервера? Небось на шаред хостинге лимита достигли?
    А контент от бинга за какое время получаете?
    Попробуйте запустить ваш скрипт на локалке с какой нибудь мощной конфигурацией компьютера.
     
  5. SocMaster

    SocMaster aka Hakerok

    Регистр.:
    26 июл 2011
    Сообщения:
    202
    Симпатии:
    47
    Нет, выделенный сервер, Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz 2668.000 Mhz X 8 оперативки в пределах 50 гигов
    Стоит nginx + php-fpm
    По нагрузке качели [​IMG]
    в php-fpm slow logs указывают на эту функцию парсинга текста
    Скрипт когда все идеально, время загрузки до 1сек это функция из доргена одного. вот на неё и указывает сервер что виснет со временем
     
  6. PirateGod

    PirateGod Постоялец

    Регистр.:
    6 июн 2014
    Сообщения:
    80
    Симпатии:
    72
    Обязательно отрабатывать моментально? Может слипы проставить, а результат выполнения скрипта всё равно будет, не важно на сколько быстро.
     
  7. SocMaster

    SocMaster aka Hakerok

    Регистр.:
    26 июл 2011
    Сообщения:
    202
    Симпатии:
    47
    Началось все с того, что сервер просто падал на время из-за нагрузки, глянул, там в цикле file_get_contents
    поставил мультикурл, время с 5-8 сек упало до 1-2
    сервер начал жить дольше намного. но что то со временим подвисает с нагрузкой

    А куда слипы поставить?
     
    Последнее редактирование модератором: 7 сен 2015
  8. PirateGod

    PirateGod Постоялец

    Регистр.:
    6 июн 2014
    Сообщения:
    80
    Симпатии:
    72
    Проанализируйте, в каком цикле у вас самая ресурсоемкая задача, там и ставьте 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 . ". ";
            }
        }
    И на боевом сервере уберите везде комментарии. Это конечно экономия на спичках...
     
    SocMaster нравится это.
  9. Qwest-fx

    Qwest-fx Постоялец

    Регистр.:
    3 апр 2007
    Сообщения:
    129
    Симпатии:
    39
    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);
     
    latteo и SocMaster нравится это.
  10. latteo

    latteo Эффективное использование PHP, MySQL

    Moderator
    Регистр.:
    28 фев 2008
    Сообщения:
    1.450
    Симпатии:
    1.244
    Плохой совет:
    2015-09-07_22-13_php_multicurl_vs_fgc.jpg
    Проводил несколько замеров, multicurl в 2-2,5 раза быстрее file_get_contents

    Совет правильный, а вот место для usleep плохое - весь этот цикл меньше 0,01 секунды выполняется

    А вот это хороший совет, только время надо от 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), но суть не меняется...
     
    Последнее редактирование: 9 сен 2015
    SocMaster нравится это.
Статус темы:
Закрыта.