Высокие нагрузки

Тема в разделе "PHP", создана пользователем phillip, 3 апр 2010.

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

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    Сделал для доргена модуль. Юзер заходит на сайт, тогда модуль "на лету" через fopen() открывает файл с ключами, и вставляет рендомные строки. в файле 200к строк. Но считываем мы не все, а именно рендомные. fseek, затем fgets. когда 15к запросов идет, все падает. как оптимизировать?
     
  2. Abliganto

    Abliganto Постоялец

    Регистр.:
    30 ноя 2009
    Сообщения:
    111
    Симпатии:
    46
    А как вы узнаёте кол-во строк в файле? Или скрипту заранее известно это количество?

    Если можно, лушче сопроводить вопрос примером кода. Если скрипт сам узнаёт кол-во строк каждый раз - это будет ооочень тормозить. Если заранее известно и надо только считывать интервалы байтов, то будет быстрее.

    По-уму надо всё хранить в памяти, но на шаред хостинге такой роскоши нет. Советую каждую операцию заключить в microtime(true) и посмотреть где именно существует узкое место. Если узкое место явно не наблюдается, то надо думать дальше.
     
    phillip нравится это.
  3. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    окей! спасибо за ответ!
    ну во-первых скрипт поделен на две части, клиентскую и серверную. Собственно, юзер заходит на клиентскую часть, и в файле идет курлом примерно такой вызов:
    PHP:
    $query_str 'mod=warez&mod_keys='.$mod_keys.'&one_key=true&klient_domen='.$klient_domen.'&module_path='.$module_path;
    $ch curl_init();  
    curl_setopt($chCURLOPT_URL,$dorgen_adr.'mod-reqs.php');  
    curl_setopt($chCURLOPT_TIMEOUT30);
    curl_setopt($chCURLOPT_HEADER0); 
    curl_setopt($chCURLOPT_POST1);
    curl_setopt($chCURLOPT_RETURNTRANSFER1); 
    curl_setopt($chCURLOPT_POSTFIELDS$query_str); 
    $res curl_exec($ch); 
    curl_close($ch);
    $contentpreg_replace('/'.$t.'/'$res$content1);
    Это собственно чего означает. Курлом посылаем запрос на серверную часть, ответ от серверной части вставляем в контент страницы. А ответ представляет собой список линков. То есть... Вот примерно серверная часть:
    PHP:
    if (isset($_POST['mod']) and $_POST['mod']=='warez' and isset ($_POST['c_lnks'])) {

    $f fopen('doors_datas/keywords/'.$_POST['mod_keys'].'.txt',  'r');
    $szfilesize('doors_datas/keywords/'.$_POST['mod_keys'].'.txt');

    for (
    $x=0$x<$_POST['c_lnks']; $x++) {
    fseek($frand(0$sz)); fgets($f);
    $k=trim(fgets($f));
    echo 
    '<a href="http://'.$_POST['klient_domen'].'/'.$_POST['module_path'].'/'.urlencode($k).'.html">'.$k.'</a><br />'
    }
    fclose($f);
    }
    Вкратце, что это за механизм. Нам переданы POST данные, с указанием названия текстового файла. Этот файл открываем через fopen, далее получаем его размер через filesize и потом сперва берем обрывок строки с рендомным смещением fseek($f, rand(0, $sz)); и тут же берем целую строку fgets($f); Таким образом, незамысловато набираем набор рендомных строк из файла.
    Очень прошу помочь, работает медленно!
     
  4. potuga

    potuga

    Регистр.:
    22 сен 2009
    Сообщения:
    376
    Симпатии:
    91
    В серверном скрипте работай с БД. Будет быстрее файла.

    Если ты на *nix, то попробуй:

    PHP:
    function getFileLine($file$line) {
        return 
    trim(exec("head -n $line $file | tail -n 1"));
    }
    но учти, что при 15к запросов это не спасет. Так что остается БД
     
    phillip нравится это.
  5. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    пробовал с бд, мускулем родным. что-то тоже медленно. Наверно я как-то примитивно делаю. а мб в оперативке держать? 400мб доступно
     
  6. Abliganto

    Abliganto Постоялец

    Регистр.:
    30 ноя 2009
    Сообщения:
    111
    Симпатии:
    46
    Самое узкое место (помимо сети и чтения файла) - это rand() Смею предположить, что из БД вы вытягивали данные путём такого запроса:
    Код:
    SELECT * FROM keys ORDER BY RAND() LIMIT x
    ? это будет выполняться ооочень медленно из-за ORDER BY RAND(), надо использовать другие методы.

    И не советую использовать обычный rand() тут я писал почему: http://www.nulled.ws/showthread.php?t=169519 (т.к. он вовсе не случаен)
     
    phillip нравится это.
  7. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    в этом скрипте у меня с бд ничего не связано как раз. насчет rand- я всегда пользовал mt_rand, а тут как-то так вышло, сам не заметил. А в остальном, кроме rand?
    тему посмотрел, хорошо описано, спасибо
     
  8. Abliganto

    Abliganto Постоялец

    Регистр.:
    30 ноя 2009
    Сообщения:
    111
    Симпатии:
    46
    А что ещё можно сделать? Можно большой файл разбить на несколько маленьких, но мне кажется, это ничего не даст. Других методов извлечения строк из файла нет. Ваш метод немного избыточен из-за лишнего вызова fgets(), но я думаю строк читается не много и это не сильно накладно. Когда речь идёт о высоких нагрузках, значение имеет абсолютно любая мелочь.

    Если хранить всё в памяти, то нужно использовать key-value БД вроде APC или memcached или Redis. Mysql при правильном подходе тоже должен быстро справляться.

    А ваш rand() будет генерить одинаковые страницы (одни и те же кеи будет вытаскивать) т.е. одну и ту же последовательность.
     
  9. phillip

    phillip

    Регистр.:
    4 сен 2007
    Сообщения:
    413
    Симпатии:
    15
    ну да. исходя из вашей статьи на которую дали линк, я это понял. Изменю.
    А насчет memcache и APC. скрипт надо будет сильно переделывать? или их просто включаешь и все, все само собой работает? Мб где-то есть наглядный мануал как их использовать. Поискал- все в основном освещают темы по типу "мемкеш сравнили с APC, мемкеш хорош потому-то, а этот вот поэтому". А конкретная инструкция что измени скрипт вот так, чтобы было круто. нема :nezn:
    Давно увиливал от этой темы, но похоже без этих самых мемкеш и APC не обойтись
     
  10. Abliganto

    Abliganto Постоялец

    Регистр.:
    30 ноя 2009
    Сообщения:
    111
    Симпатии:
    46
    Использовать просто. Достаточно открыть мануал по PHP, там всё есть.
    PHP:
    $lines apc_get'dorgen_lines_cnt' );
    $r rand0$lines );
    $randomLine apc_get'dorgen_line_' $r );
    У остальных примерно такой же API. Тут всё зависит от того какой у вас сервер. Я бы на вашем месте всё же попробывал MySQL т.к. он работает очень быстро. Самое узкое место будет подключение и возможно переполнение допустимого кол-ва открытых соединений, можно, но очень не рекомендуется использовать постоянные соединения. Можно получить 100 запросов в секунду. Что для этого нужно:
    1) Таблица со строками myisam с автоинкрементным полем без дырок (все записи должны идти по порядку)
    2) Нужно знать сколько строк всего.
    3) В PHP генерируете массив случайных чисел и вставляете в запрос
    Код:
    SELECT `line` FROM `dorgen_lines` WHERE `id` IN ( 1, 15, 23, 234, 53 )
    И если и это бы тормозило, я бы поставил Sphinx search у него индексы ещё быстрее.

    Добавлено через 1 минуту
    P.S. в майскул можно использовать тип таблиц мемори - будет всё храниться в памяти (до перезагрузки сервера).
     
    phillip нравится это.
Статус темы:
Закрыта.