php/timeout/connection to reset сервера?

У меня есть php-скрипт, который нужно запустить в течение некоторого времени.

Что делает скрипт:

  • подключается к mysql
  • инициирует от 100 до 100 000 запросов cURL
  • каждый запрос cURL возвращает компактно декодированные данные от 1 до 2000 списков недвижимости - я использую preg-match-all, чтобы получить все данные и выполнить одну вставку mysql для каждого списка. каждый запрос никогда не превышает 1 МБ данных.

Таким образом, происходит много циклов, вставок mysql и запросов curl. Безопасный режим php отключен, и я могу успешно ini_set max-execution-time сделать что-то нелепое, чтобы позволить моему скрипту выполняться полностью.

Ну у меня проблема в том, что у скрипта или апача или чего-то в середине скрипта есть штрих и экран переходит на экран "соединение с сервером сброшено".

Любые идеи?


person Mickey    schedule 22.10.2009    source источник


Ответы (6)


Ну, если не принимать во внимание тот факт, что попытка 100 000 запросов cURL абсолютно безумна, вы, вероятно, достигли предела памяти.

Попробуйте установить ограничение памяти на что-то более разумное:

ini_set('memory_limit', '256M');

И в качестве дополнительного совета, не устанавливайте время выполнения на что-то нелепое, скорее всего, вы в конечном итоге найдете способ добиться этого с помощью скрипта, подобного этому. ;]

Вместо этого просто установите для него значение 0, функционально это эквивалентно полному отключению лимита выполнения:

ini_set('max_execution_time', 0);
person Nathan Kleyn    schedule 22.10.2009
comment
да, теперь я вижу, что мне нужно увеличить лимит памяти, но разве это плохая идея? - person Mickey; 23.10.2009
comment
@Джон: Да и нет. Не устанавливайте его выше, чем вам нужно все время, так как это предотвращает бесконечное выполнение ошибок скрипта. Представьте, если бы вы отключили ограничитель времени выполнения скрипта и ограничение памяти и случайно запустили скрипт с бесконечным циклом! Мораль этой истории: используйте его с осторожностью в подобных ситуациях, когда ничто другое не сработает, кроме как написать его для распространения или выполнения с течением времени. Кстати, я второй комментарий timdev о настройке системы очередей заданий, это действительно способ сделать это. - person Nathan Kleyn; 23.10.2009
comment
Это был лучший ответ, чем мой - я забыл, что вы можете переопределить memory_limit с помощью ini_set - person Josh; 23.10.2009
comment
просто хотел добавить, что вы можете не только установить memory_limit во время выполнения, но и настроить его несколько раз в одном и том же вызове. в сочетании с memory_get_peak_usage/memory_get_usage вы можете динамически увеличивать лимит памяти по мере необходимости во время выполнения. - person Jon B; 16.12.2014

Много идей:

1) Не делайте этого внутри HTTP-запроса. Напишите php-скрипт командной строки для его управления. При необходимости вы можете использовать веб-скрипт, чтобы запустить его.

2) Вы должны иметь возможность установить max_execution_time равным нулю (или вызвать set_time_limit(0)), чтобы гарантировать, что вас не закроют из-за превышения лимита времени.

3) Похоже, вы действительно хотите преобразовать это во что-то более разумное. Подумайте о настройке небольшой системы очередей заданий и наличии php-скрипта, который разветвляет несколько дочерних элементов, чтобы пережевывать всю работу.

Как говорит Джош, посмотрите на свой error_log и узнайте, почему вас сейчас отключают. Попробуйте выяснить, сколько памяти вы используете — это может быть проблемой. Попробуйте установить max_execution_time равным нулю. Возможно, это поможет вам быстро добраться туда, куда вам нужно.

Но в долгосрочной перспективе кажется, что у вас слишком много работы внутри одного http-запроса. Убери это из http, разделяй и властвуй!

person timdev    schedule 22.10.2009
comment
не знал об этом трюке 0, приятно знать. не уверен, как это сделать, кроме как в php-скрипте. - person Mickey; 23.10.2009

Вы можете установить неопределенный тайм-аут, изменив файл PHP.ini и установив переменную выполнения скрипта.

Но вы также можете подумать о небольшом изменении архитектуры. Сначала рассмотрим подход «Запусти и забудь» при получении 100 000 запросов на завивку. Во-вторых, рассмотрите возможность использования «wget» вместо curl.

Вы можете выполнить простое «wget URL -o UniqueFileName &». Это вызовет веб-страницу, сохранит ее в «уникальном» имени файла и все это в фоновом режиме.

Затем вы можете перебирать каталог файлов, greping (preg_matching) данные и выполнять вызовы БД. Переместите файлы по мере их обработки в архив и продолжайте итерацию до тех пор, пока файлы не закончатся.

Думайте о каталоге как об «очереди», и пусть один процесс просто обрабатывает файлы. Пусть второй процесс просто выйдет и получит данные веб-страницы. Вы можете добавить третий процесс, который вы можете «мониторить», который работает независимо и просто сообщает статистику моментальных снимков. Два других могут быть просто «веб-сервисами» без интерфейса.

Этот тип многопоточности действительно мощный и очень малоиспользуемый ИМХО. Для меня это истинная сила Интернета.

person ChronoFish    schedule 22.10.2009

У меня была такая же проблема при получении данных из MySQL через PHP, которые содержали специальные символы, такие как умляуты ä, ö, ü, амперсанд и т. д. Соединение было сброшено, и я не нашел ошибок ни в журнале apache, ни в журналах php. Сначала я убедился в PHP, что я правильно обращался к символам, установленным в БД, с помощью:

mysql_query("SET NAMES 'latin1' COLLATE 'latin1_german2_ci'");

mysql_query("SET CHARACTER SET 'latin1'");

Then, finally, I resolved the problem with this line in PHP:

mysql_query("SET character_set_connection='latin1'");
person MoR    schedule 16.02.2012

100 000 запросов cURL??? Ты сумасшедший. Разбейте эти данные!

person Byron Whitlock    schedule 22.10.2009
comment
каждый раз, когда клиент добавляет новый MLS, он должен получить от 1000 до 10 000 списков - я могу получить все списки примерно за 5 запросов cURL... но мне нужно сделать 1 запрос cURL на список, чтобы получить изображения для него. - person Mickey; 23.10.2009
comment
@John: Как насчет написания класса, который содержит функции для извлечения одного элемента за раз. Вы можете перебрать все списки и создать экземпляр класса один раз для каждого, гарантируя в процессе, что при уничтожении класса память cURL также освобождается. - person Nathan Kleyn; 23.10.2009
comment
@John: По сути, вы просто хотите убедиться, что вы не извлекаете одни и те же данные снова и снова, тратя впустую циклы и пропускную способность в процессе. Настроив очередь заданий с некоторым описанием и сохранив каждую полученную страницу в базе данных, вы можете легко предотвратить это. - person Nathan Kleyn; 23.10.2009
comment
Это заставило бы скрипт работать еще дольше, потому что прямо сейчас он выполняет один запрос cURL для входа в систему, а затем выполняет все запросы cURL в цикле, а затем выполняет запрос cURL для выхода из системы. поэтому вместо входа в систему (цикл 20 раз) выход из системы //22 запроса на завивание будет выполнено 20*3 //60 запросов на завивание - ваше предложение определенно поможет решить проблему с памятью :( Должен быть способ освободить часть памяти, которая мне больше не нужна, не существует? после того, как он делает одну вещь, почему php пытается запомнить ее до конца, кажется чрезмерной. - person Mickey; 23.10.2009
comment
Я никогда не получаю одни и те же данные дважды. - person Mickey; 23.10.2009
comment
@John: Проблема с тем, как вы это делаете сейчас, заключается в том, что, хотя это не занимает столько времени, сколько предлагаемый нами метод, он делает все сразу и убивает сервер в процессе. Мы предлагаем снизить скорость запросов до одного или около того и разделить их на один вызов cURL внутри отдельного класса для каждого запроса, чтобы убедиться, что память очищается после каждого запроса. - person Nathan Kleyn; 23.10.2009
comment
Да, я ini_set память на что-то нелепое и заставил мой скрипт отправлять мне по электронной почте get_memory_usage каждый раз, когда он делал запрос на завивку, чтобы я мог видеть, где он умирает, но ... даже с памятью ini_set скрипт все еще умирает.. Я тяжело возглавил, извините, но похоже, что мне придется пойти по маршруту Натана в этом :( - person Mickey; 23.10.2009

Что в апачском error_log? Вы достигли предела памяти?

РЕДАКТИРОВАТЬ: Похоже, вы достигли предела памяти. У вас есть доступ к PHP.ini? Если это так, вы можете поднять там memory_limit. Если нет, попробуйте запустить исполняемые файлы curl или wget, используя exec или < a href="http://us3.php.net/manual/en/function.shell-exec.php" rel="nofollow noreferrer">shell_exec, таким образом, они запускаются как отдельные процессы, не используя Память PHP.

person Josh    schedule 22.10.2009
comment
Да. Я нуб извините: Допустимый размер памяти 100663296 байт исчерпан (пробовал выделить 2975389 байт) - person Mickey; 23.10.2009
comment
Это может звучать еще более нубски, но нельзя ли просто ob_flush/flush по всему сценарию или в определенных его частях? - person Mickey; 23.10.2009
comment
@John: Нет, буфер - это только одна часть используемой памяти. Функции cURL используют довольно много памяти для себя. - person Nathan Kleyn; 23.10.2009
comment
Ну почему он держит каждый запрос в памяти? Разве он не избавится от старого запроса в памяти, когда запустит новый? - person Mickey; 23.10.2009
comment
@John: Нет. Поскольку cURL является внешней библиотекой, для модели управления памятью PHP очень сложно правильно избавиться от нее. Часто это означает, что если вызовы cURL не заключены в блок (класс или даже функцию), они не будут правильно удалены. - person Nathan Kleyn; 23.10.2009
comment
@John: Смотрите мой отредактированный ответ, чтобы узнать, как увеличить лимит памяти или снизить использование памяти. - person Josh; 23.10.2009
comment
Джош, спасибо за все советы. Мне потребовалась целая вечность, чтобы заставить этот кудрявый материал работать. Он должен использовать файлы cookie, чтобы я оставался в системе. Не уверен, смогу ли я сделать это с помощью wget... или как я вообще буду делать это с помощью wget. С моими ограниченными знаниями о curl я просто подумал, что имеет смысл повторно использовать дескриптор curl, но тот факт, что он не освобождает память до самого конца, меня смущает :( - person Mickey; 23.10.2009