Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Страницы 1
Имеется 10к html документов. В них обычные таблицы которые я через symfony dom crawler обхожу в цикле, и забираю нужную инфу.
// Выше в коде
set_time_limit(0);
/**
* Init crawler
*
* @return \Illuminate\Http\Response
* @throws \Exception
*/
public function init()
{
Log::info("Parsing Started \n" . $this->convert(memory_get_usage(true)));
// If no pending links in db
if(is_null($this->link)) {
return Response::make('Success', 200);
}
if($this->link->exists) {
$this->setDocument($this->link->document);
}
try {
Log::info("Add content to crawler \n" . $this->convert(memory_get_usage(true)));
$this->crawler->addHtmlContent($this->loadPage());
Log::info("Content added \n" . $this->convert(memory_get_usage(true)));
$this->searchLinks();
Log::info("Links found \n" . $this->convert(memory_get_usage(true)));
$this->storeParsedLinks();
Log::info("Links saved \n" . $this->convert(memory_get_usage(true)));
$this->clear();
Log::info("Crawler cleaned \n" . $this->convert(memory_get_usage(true)));
$this->writeToLog('Parsing finished');
} catch (\Exception $e) {
$this->writeToLog('ERROR: ' . $e->getMessage());
$this->link->setParsed();
}
$this->link = $this->link->getFirstPending();
Log::info("Begin recursive \n" . $this->convert(memory_get_usage(true)));
$this->init();
}
И вот где мне кажется память утекает судя по логам.
Пришлось этот метод, и метод получения ссылок переписать на чистые php функции для работы с массивами (array_unique(), array_diff(), array_filter()). Так стало улетать по 2мб памяти.
До этого все операции с массивами происходили методами коллекции,и память утекала на 40мб
/**
* Store parsed links to db
*
* @return void
*/
private function storeParsedLinks(): void
{
$links = $this->getLinks();
Log::info("Found " . count($links) . " links \n" . $this->convert(memory_get_usage(true)));
$dbLinks = $this->link->getMissed($links);
$newLinks = array_diff($links, $dbLinks);
Log::info("Unique " . count($newLinks) . " links \n" . $this->convert(memory_get_usage(true)));
foreach ($newLinks as $link) {
$this->link->store($link);
}
}
[2019-12-25 15:01:49] local.INFO: Parsing Started 20 mb [2019-12-25 15:01:49] local.INFO: Add content to crawler 20 mb [2019-12-25 15:01:51] local.INFO: Content added 20 mb [2019-12-25 15:01:51] local.INFO: Links found 20 mb [2019-12-25 15:01:51] local.INFO: Found 480 links 20 mb [2019-12-25 15:01:51] local.INFO: Unique 0 links 20 mb [2019-12-25 15:01:51] local.INFO: Links saved 20 mb [2019-12-25 15:01:51] local.INFO: Crawler cleaned 20 mb [2019-12-25 15:01:51] local.INFO: Begin recursive 20 mb [2019-12-25 15:01:55] local.INFO: Parsing Started 20 mb [2019-12-25 15:01:55] local.INFO: Add content to crawler 20 mb [2019-12-25 15:01:56] local.INFO: Content added 20 mb [2019-12-25 15:01:56] local.INFO: Links found 20 mb [2019-12-25 15:01:56] local.INFO: Found 482 links 20 mb [2019-12-25 15:01:56] local.INFO: Unique 0 links 22 mb [2019-12-25 15:01:56] local.INFO: Links saved 22 mb [2019-12-25 15:01:56] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:01:56] local.INFO: Begin recursive 22 mb [2019-12-25 15:02:02] local.INFO: Parsing Started 22 mb [2019-12-25 15:02:02] local.INFO: Add content to crawler 22 mb [2019-12-25 15:02:04] local.INFO: Content added 22 mb [2019-12-25 15:02:04] local.INFO: Links found 22 mb [2019-12-25 15:02:04] local.INFO: Found 488 links 22 mb [2019-12-25 15:02:04] local.INFO: Unique 3 links 22 mb [2019-12-25 15:02:04] local.INFO: Links saved 22 mb [2019-12-25 15:02:04] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:02:04] local.INFO: Begin recursive 22 mb [2019-12-25 15:02:08] local.INFO: Parsing Started 22 mb [2019-12-25 15:02:08] local.INFO: Add content to crawler 22 mb [2019-12-25 15:02:09] local.INFO: Content added 22 mb [2019-12-25 15:02:09] local.INFO: Links found 22 mb [2019-12-25 15:02:09] local.INFO: Found 488 links 22 mb [2019-12-25 15:02:09] local.INFO: Unique 0 links 22 mb [2019-12-25 15:02:09] local.INFO: Links saved 22 mb [2019-12-25 15:02:09] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:02:09] local.INFO: Begin recursive 22 mb ... // Спустя какое то время память с 20мб до 64 доходит [2019-12-25 15:15:53] local.INFO: Parsing Started 62 mb [2019-12-25 15:15:53] local.INFO: Add content to crawler 62 mb [2019-12-25 15:16:00] local.INFO: Content added 62 mb [2019-12-25 15:16:00] local.INFO: Links found 62 mb [2019-12-25 15:16:00] local.INFO: Found 480 links 62 mb [2019-12-25 15:16:00] local.INFO: Unique 0 links 64 mb [2019-12-25 15:16:00] local.INFO: Links saved 64 mb [2019-12-25 15:16:00] local.INFO: Crawler cleaned 64 mb [2019-12-25 15:16:00] local.INFO: Begin recursive 64 mb [2019-12-25 15:16:04] local.INFO: Parsing Started 64 mb [2019-12-25 15:16:04] local.INFO: Add content to crawler 64 mb [2019-12-25 15:16:06] local.INFO: Content added 64 mb [2019-12-25 15:16:06] local.INFO: Links found 64 mb [2019-12-25 15:16:06] local.INFO: Found 481 links 64 mb [2019-12-25 15:16:06] local.INFO: Unique 0 links 64 mb [2019-12-25 15:16:06] local.INFO: Links saved 64 mb [2019-12-25 15:16:06] local.INFO: Crawler cleaned 64 mb [2019-12-25 15:16:06] local.INFO: Begin recursive 64 mb
Не могу понять почему чистильщик не очищает память?
Изменено TrueKanonir (25.12.2019 13:46:26)
Не в сети
Не могу понять почему чистильщик не очищает память?
А какой лимит по памяти у процесса (memory_limit)? Может ему и не нужно, т.к. памяти еще хватает.
Попробуй gc_collect_cycles(); - это вызовет GC принудительно.
Точнее сказать нельзя, потому что не известно, что там в getMissed().
$this->convert(memory_get_usage(true)));
Учти, что:
real_usage
Set this to TRUE to get total memory allocated from system, including unused pages. If not set or FALSE only the used memory is reported.
Так что статистика может быть нерепрезентативна. Сравни с memory_get_usage(false).
Не в сети
- А какой лимит по памяти у процесса (memory_limit)?
memory_limit = 1536M
Когда использовались коллекции, и память до 1.56 гб доходила. Процесс падал с 500 ошибкой и месагой *out of mamory limit…* ну это и понятно
- Попробуй gc_collect_cycles();
Ниже второй код с его использованием. разницы нет.
- Сравни с memory_get_usage(false).
// memory_get_usage(false)
[2019-12-26 10:56:45] local.INFO: Parsing Started
17.31 mb
[2019-12-26 10:56:45] local.INFO: Add content to crawler
17.36 mb
[2019-12-26 10:56:46] local.INFO: Content added
17.37 mb
[2019-12-26 10:56:46] local.INFO: Links found
17.44 mb
[2019-12-26 10:56:46] local.INFO: Found 484 links
17.45 mb
[2019-12-26 10:56:46] local.INFO: Unique 0 links
17.71 mb
[2019-12-26 10:56:46] local.INFO: Links saved
17.67 mb
[2019-12-26 10:56:46] local.INFO: Crawler cleaned
17.65 mb
[2019-12-26 10:56:46] local.INFO: Begin recursive
17.71 mb
...
[2019-12-26 11:03:08] local.INFO: Parsing Started
37.4 mb
[2019-12-26 11:03:08] local.INFO: Add content to crawler
37.42 mb
[2019-12-26 11:03:10] local.INFO: Content added
37.42 mb
[2019-12-26 11:03:10] local.INFO: Links found
37.5 mb
[2019-12-26 11:03:10] local.INFO: Found 486 links
37.49 mb
[2019-12-26 11:03:10] local.INFO: Unique 0 links
37.76 mb
[2019-12-26 11:03:10] local.INFO: Links saved
37.72 mb
[2019-12-26 11:03:10] local.INFO: Crawler cleaned
37.7 mb
[2019-12-26 11:03:10] local.INFO: Begin recursive
37.69 mb
// memory_get_usage(false) + gc_collect_cycles();
[2019-12-26 11:05:09] local.INFO: Parsing Started
17.14 mb
[2019-12-26 11:05:09] local.INFO: Add content to crawler
17.16 mb
[2019-12-26 11:05:11] local.INFO: Content added
17.16 mb
[2019-12-26 11:05:11] local.INFO: Links found
17.24 mb
[2019-12-26 11:05:11] local.INFO: Found 487 links
17.24 mb
[2019-12-26 11:05:11] local.INFO: Unique 0 links
17.51 mb
[2019-12-26 11:05:11] local.INFO: Links saved
17.47 mb
[2019-12-26 11:05:11] local.INFO: Crawler cleaned
17.45 mb
[2019-12-26 11:05:11] local.INFO: Begin recursive
17.51 mb
...
[2019-12-26 11:12:31] local.INFO: Parsing Started
38.64 mb
[2019-12-26 11:12:31] local.INFO: Add content to crawler
38.66 mb
[2019-12-26 11:12:34] local.INFO: Content added
38.66 mb
[2019-12-26 11:12:34] local.INFO: Links found
38.74 mb
[2019-12-26 11:12:34] local.INFO: Found 480 links
38.74 mb
[2019-12-26 11:12:34] local.INFO: Unique 0 links
39 mb
[2019-12-26 11:12:34] local.INFO: Links saved
38.9 mb
[2019-12-26 11:12:34] local.INFO: Crawler cleaned
38.88 mb
[2019-12-26 11:12:34] local.INFO: Begin recursive
38.93 mb
- Точнее сказать нельзя, потому что не известно, что там в getMissed()
Ну тут обычный запрос в бд, что бы выбрать уже имеющиеся ссылки, а затем сравнить их со всеми найденными ссылками что бы в итоге получить новые уникальные ссылки которых нет в базе.
Да, метод назван не явно, но тут и скрипт написан на коленке и рефакторинга еще не делал.
/**
* Check if link already exists
*
* @param array $links
* @return mixed
*/
public function getMissed(array $links)
{
return $this->whereIn('link', $links)->pluck('link')->all();
}
Не в сети
Незнаю как теперь быть, так как файлов еще очень много (помимо этих 10к). Эти все файлы за 0 лет работы скопились.
Хотел что бы какой нибудь из продаванов нажал пару кнопок, скрипт в очередь встал, и забыть про него.
Но теперь блин придется по ходу следить, или использовать шедулер что бы заного процесс запускать когда память сядит…
Не в сети
Ниже второй код с его использованием. разницы нет.
Значит что-то держит память, ссылки не дохлые.
Ну тут обычный запрос в бд, что бы выбрать уже имеющиеся ссылки, а затем сравнить их со всеми найденными ссылками что бы в итоге получить новые уникальные ссылки которых нет в базе.
Видимо, здесь и утекает. В Laravel ногу сломишь, пока поймешь, где, что и кто не очистил (я еще в L3 находил утечки, даже Тейлору писал, а L3 был на порядок проще того, что сейчас), поэтому попробуй переписать этот кусок в виде сырого запроса, благо он у тебя простой. Если это не поможет - тогда попробуй и вовсе его закомментировать и заменить на чтение данных из файла (просто для тестов) через json_decode(file_get_contents()) или require() (если данные в виде PHP-кода - var_export()). Если действительно утечка здесь, то после замены память будет в норме, сколько бы итераций не прошло.
Эти все файлы за 0 лет работы скопились.
Много файлов за 0 лет работы скопилось?
Но теперь блин придется по ходу следить, или использовать шедулер что бы заного процесс запускать когда память сядит…
А чего ты хотел, Laravel оптимизированным по памяти никак не назовешь, с его кучей прокладок и фасадов. Он хорош в отдельно взятой области - обработке запросов от клиента. В этом плане никакие утечки не страшны, потому что в типичном запросе GC может вообще не вызываться, запрос быстро отработал и всю память собрали принудительно. А у тебя, видимо, тысячи объектов, и ты при этом хочешь плюшки Laravel в виде коллекций и ORM... Не, так не бывает.
Не в сети
- Видимо, здесь и утекает. В Laravel ногу сломишь, пока поймешь, где, что и кто не очистил (я еще в L3 находил утечки, даже Тейлору писал, а L3 был на порядок проще того, что сейчас), поэтому попробуй переписать этот кусок в виде сырого запроса, благо он у тебя простой. Если это не поможет — тогда попробуй и вовсе его закомментировать и заменить на чтение данных из файла (просто для тестов) через json_decode(file_get_contents()) или require() (если данные в виде PHP-кода — var_export()). Если действительно утечка здесь, то после замены память будет в норме, сколько бы итераций не прошло
- Много файлов за 0 лет работы скопилось?
Ыть, очепятолся. За 10 лет))
Эти все файлы были раньше базой в лотусе (таможенная софтина для учета экспортеров / импортеров). По сути, тот же ексель, только в своем формате. Ну, и кто то решил, что удобно будет экспортировать все в html таблицы…
- А чего ты хотел, Laravel оптимизированным по памяти никак не назовешь, с его кучей прокладок и фасадов. Он хорош в отдельно взятой области — обработке запросов от клиента. В этом плане никакие утечки не страшны, потому что в типичном запросе GC может вообще не вызываться, запрос быстро отработал и всю память собрали принудительно. А у тебя, видимо, тысячи объектов, и ты при этом хочешь плюшки Laravel в виде коллекций и ORM… Не, так не бывает
Крайняк, если не решу проблему, то на питоне все сделаю
Proger_XP, спасибо за помощ!
Не в сети
Крайняк, если не решу проблему, то на питоне все сделаю
На PHP вполне нормально реализуются долгоживущие парсеры. У самого PHP утечек нет, у меня бывали и бывают процессы, которые стартуют с ОС и работают, пока не перезагрузишь. Это именно проблема (или "нецелевое использование" - как угодно) Laravel. В твоем случае достаточно переписать пару мест на "более голый" PHP (степень "голости" зависит от тебя). Python - это слишком радикальное решение, ИМХО.
В конце концов, "whereIn()->pluck()" это тот же PDO + array_column(), 2-3 строчки максимум.
Не в сети
- На PHP вполне нормально реализуются долгоживущие парсеры. У самого PHP утечек нет, у меня бывали и бывают процессы, которые стартуют с ОС и работают, пока не перезагрузишь. Это именно проблема (или «нецелевое использование» — как угодно) Laravel. В твоем случае достаточно переписать пару мест на «более голый» PHP (степень «голости» зависит от тебя). Python — это слишком радикальное решение, ИМХО.
Дня 2 назад опять занялся этой задачей. И в итоге вроде нашел в чем проблема.
[2019-12-29 13:10:59] local.INFO: Parsing Started
17.52 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:10:59] local.INFO: Add content to crawler
17.54 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Content added
17.54 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Links found
17.63 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Found 498 links
17.62 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Unique 3 links
17.92 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Links saved
17.86 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Crawler cleaned
17.84 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Begin recursive
17.9 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:05] local.INFO: Parsing Started
17.9 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:05] local.INFO: Add content to crawler
17.92 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Content added
17.93 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Links found
18.01 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Found 499 links
18.01 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Unique 7 links
18.3 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Links saved
18.24 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Crawler cleaned
18.22 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Begin recursive
18.28 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:12] local.INFO: Parsing Started
18.28 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:12] local.INFO: Add content to crawler
18.3 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Content added
18.31 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Links found
18.41 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Found 498 links
18.4 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Unique 5 links
18.69 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Links saved
18.63 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Crawler cleaned
18.62 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Begin recursive
18.68 mb
this 592| manager591| link 1835| log 594
Если смотреть на id после памяти, то объект ссылки пересоздается (судя по id). Ну это и понятно, так как идут запросы вида
// Модель Link.php
/**
* Get first pending link
*
* @return mixed
*/
public function getFirstPending()
{
return $this->oldest()
->where([
'state' => self::PENDING
])
->first();
}
/**
* Set parsed state
*
* @return mixed
*/
public function setParsed()
{
return $this->update([
'state' => self::PARSED
]);
}
/**
* Set failed state
*
* @return mixed
*/
public function setFailed()
{
return $this->update([
'state' => self::FAILED
]);
}
Ну а там внутри (в самих методах модели) newEloquentBuilder() которые и порождают новые объекты, которые скорее всего не умирают после отработки, а висят в памяти.
- В конце концов, «whereIn()->pluck()» это тот же PDO + array_column(), 2-3 строчки максимум.
После праздников перепишу все на сырые запросы
Изменено TrueKanonir (31.12.2019 16:36:51)
Не в сети
Страницы 1