Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Помогите навести порядок в некотором агрегаторе...

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Без описания
nkl
Отправлено: 09 Декабря, 2014 - 08:38:52
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




Доброго времени суток, передо мной давно стоит задача быстрой агрегации больших объемов данных, для последующего их возврата в REST-сервисе через ajax. Так вот, сама логика агрегации написана полностью, запилена внушительных размеров БД, операторы исправно модифицируют и подготавливают исходные данные для передачи их в REST-сервис. Все это дело сейчас работает через cron:
Цитата:

get_feeds.php - собственно получение свежих данных, работает порядка 2-3 мин, потому что парсит большие (~100-200 Мб) xml-файлы. Желательно делать это каждый 2-3 мин, т.к. данные динамично обновляются и REST-сервис должен отдавать самые свежие данные, но сейчас делаю раз в 10 мин, иначе возникают проблемы, которые я опишу чуть ниже...
update_feeds_alias.php - т.к. соединение данных происходит по текстовым аббревиатурам - этот скрипт проверят базу аббревиатур и дописывает те, что еще нет в БД для каждого источника xml-данных. Делается 2 раза в час, т.к. не так уж и часто появляются новые псевдонимы (делается порядка 15-20 мин., т.к. база псевдонимов по каждому источнику данных уже порядка 60к строк, плюс идет полнотекстовый поиск, а не выборка по какому-то айдишнику)
aggregate.php - собственно сам процесс выявления идентичных строк со всех источников и соединение их под один псевдоним (который сопоставили операторы). По идее должен происходить сразу же после того, как были получены распарсены xml-данные, но делается тоже по крону ибо процесс долгий.
add_redy_events.php - это скрипт выявляет только идентичные строки со всех источников и пишет их в БД, таким образом, что бы в последствии к этим строкам можно было обращаться по нашему уникальному айдишнику. Должен делаться тоже после того, как получены xml-данные.
update_cfs_to_redy_events.php - это собственно скрипт для обновления инфы по выявленным строкам для каждого источника данных

Уф. Вроде все описал конспиративно) Так вот, в чем проблема, вся эта херня должна работать очень быстро, все эти скрипты берут исходные данные, модифицируют их для дальнейшей стадии обработки сохраняя их в промежуточные таблицы БД, т.к. в оперативки все это держать не реально, а следующий скрипт уже берет модифицированные данные и еще больше их модифицирует. В общем такая вот сложная цепочка обработки происходит, с хранением промежуточных итогов вычисления в промежуточных таблицах.

В чем собственно проблема: если весь этот алгоритм работает раз в 10 мин, то все норм, но если увеличить периодичность этого пересчета и парсинга, то сервер начинает загибаться, т.к. еще не успел отработать один экземпляр скрипта, как крон запускает его еще раз и еще раз, в итоге получается каша, а все скрипты должны работать строго в заданном порядке. Пробую решить эту задачу через GEARMAN и SUPERVISOR (для управления воркерами), но чувствую я, что эти вещи не для этих целей предназначены, а может это просто я тупой и не до конца разобрался в мат.части серверов очередей. Может опытное сообщество моего любимого форума подскажет мне как навести порядок в этой цепочке? Растерялся
 
 Top
DeepVarvar Супермодератор
Отправлено: 09 Декабря, 2014 - 09:16:01
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Решение то на поверхности.
С каждым новым запущенным процессом создавать PID файл, а по завершении удалять его.
Тогда хоть раз в минуту запускать по крону, но проверять, если PID файл есть, то сворачивать свои дела до момента пока PID файла не будет.
Ну а общая оптимизация работы, чтобы быстрее завершало, это уже другой вопрос.
 
 Top
nkl
Отправлено: 09 Декабря, 2014 - 09:29:38
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




Да, пробовал я с этим pid-файлом делать, в начале каждого скрипта прописана эта проверка, но ска, ненадежная эта штука, вроде бы работает-работает, пока нормально, а потом херак и где нить в пол шестого утра выясняется что сервер лежит... Нахмурился Причем совершенно по непонятно причине запущено 10 экзепляров одного и того же процесса и непонятно, с чем это связано, ведь и pid-файл имеется и проверка идет, ан нет, процесс запускается еще раз...

Буду дальше крутить сервер очередей, как подсказывает начальник. Говорит, надо получить статус задачи, прежде чем еще раз добавлять её в очередь, может в этом моя проблема Растерялся
 
 Top
DeepVarvar Супермодератор
Отправлено: 09 Декабря, 2014 - 10:03:26
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Вместо пида можно еще грепать пути в пээсе, я тут чот похожее делал ранее: http://forum.php.su/topic.php?fo...58894#1320758894
 
 Top
nkl
Отправлено: 10 Декабря, 2014 - 07:27:18
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




DeepVarvar пишет:
Вместо пида можно еще грепать пути в пээсе, я тут чот похожее делал ранее: http://forum.php.su/topic.php?forum=66&topic=908&postid=1320758894#1320758894

Честно говоря не совсем понял о чем тот пример и как использовать тот класс. Попробовал сделать по мануалу, как предлагается тут http://tarlyun[dot]com/blog/2013/02/[dot][dot][dot]j-kopii-skripta/
Только у меня такой вопрос, сработает ли register_shutdown_function() в том случае, когда скрипт будет завершено аварийно (например Out of memory и т.п.)? Хотя вот тут люди пишут, что как раз для таких случаев и применяется этот вызов и не сработает он только в том случае, если нажать в консоли Ctrl+C.
 
 Top
DeepVarvar Супермодератор
Отправлено: 10 Декабря, 2014 - 08:29:45
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Цитата:
...с помощью register_shutdown_function(), которая срабатывает даже тогда, когда скрипт завершился с фатальной ошибкой (этот способ, кстати, годится для отлова почти любых ошибок, в том числе ошибок нехватки памяти)...
О как завернул. Нюню, интересно, памяти нет, т.е. более не выделяется. И тут вдруг, оппа! и выделилась для шутдауна. Эт если в ядре так сделано, что шутдаун не чувствителен к лимиту установленному в ини. А это, на минуточку, дыра. Я так вообще всю память-жрущую локику в шутдаун буду помещать, и плевать на лимиты установленные хостером например ))

Вобщем я предлагал так:
PHP:
скопировать код в буфер обмена
  1. while (1) {
  2.     sleep(1);
  3.     echo microtime(true) . PHP_EOL;
  4. }

CODE (bash):
скопировать код в буфер обмена
  1. $ /usr/bin/php /home/deep/test.php

CODE (bash):
скопировать код в буфер обмена
  1. $ ps ax | grep test
  2. 23517 ?        S      0:01 gedit /home/deep/test.php
  3. 23628 pts/0    S+     0:00 /usr/bin/php /home/deep/test.php
  4. 23631 pts/2    S+     0:00 grep test
  5.  

Только сгрепать всю строку команды, если оная выполняется, значит такую-же не запускать.
Т.е. крон запускает зиготу, которая проверяет наличие самого процесса, и если процесс уже есть, то просто завершается, если процесса нет, то понеслась:
PHP:
скопировать код в буфер обмена
  1. exec('/usr/bin/php /home/deep/test.php');
 
 Top
nkl
Отправлено: 10 Декабря, 2014 - 09:27:38
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




А может именно вызов register_shutdown_function() и резервирует необходимый объем памяти на случай вылета? Потому что уже несколько примеров почитал по этому вызову и все твердят одно, функция сработает. Хотя еще и не проверил сам.
(Добавление)
Кстати, теперь понял о чем вы (грепать пути в пээсе Улыбка ), думаю тоже рабочий вариант, но сейчас я пока погоняю это с lock-файлом, посмотрим что в итоге получиться. Кстати, в комментах к тому пример с lock-файлом, один товарищ написал, что, цитирую:
Цитата:
Зачем использовать register_shutdown_function, если lock-файл в любом случае автоматически закроется при завершении скрипта?

так ли это на самом деле? Растерялся
 
 Top
DeepVarvar Супермодератор
Отправлено: 10 Декабря, 2014 - 09:54:11
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Есть оригинальная эксклюзивная блокировка файла но насколько я знаю, пыховый LOCK_EX не является непосредственной оберткой над ней. Соответственно, если это так, то конечно, по завершению работы скрипта файл "отпустит" для других пыхоскриптов. А если это не так? Некогда щас проверять. Я всегда грепал пээс и оно точно работает.
 
 Top
nkl
Отправлено: 10 Декабря, 2014 - 10:48:16
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




Т.е. вы имели в виду это:
CODE (htmlphp):
скопировать код в буфер обмена
  1. $psax = `ps ax | grep lock_test.php`;
  2. $haystack = $psax;
  3. $needle   = '/home/user/scripts/lock_test.php';
  4.  
  5. $pos = strripos($haystack, $needle);
  6.  
  7. if ($pos === false) {
  8.     exec('/usr/bin/php ' . $needle);
  9. }else{
  10.     die("This script is running\n");
  11. }
  12.  
 
 Top
Panoptik
Отправлено: 10 Декабря, 2014 - 10:53:12
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2493
Дата рег-ции: Нояб. 2011  
Откуда: Одесса, Украина


Помог: 131 раз(а)




там нужно более умнее. у вас же есть именно пид процесса, а не его имя

вот примеры есть тут

http://stackoverflow[dot]com/questio[dot][dot][dot]-without-using-p

но там тоже варианты без напильника не всегда идут


-----
Just do it
 
 Top
DeepVarvar Супермодератор
Отправлено: 10 Декабря, 2014 - 10:57:15
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Panoptik пишет:
там нужно более умнее
Вот именно, умнее. У каждого нового процесса свой новый уникальный пид, это значит его надо где-то хранить, в файле например, значит файл надо лочить, и опять двадцать пять.
Я же предлагаю вообще на пиды не ориентироваться.
nkl пишет:
Т.е. вы имели в виду это
Да. Только $needle это вся команда от начала до конца, а не только имя запускаемого файла.
 
 Top
nkl
Отправлено: 10 Декабря, 2014 - 11:19:47
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




Цитата:
значит файл надо лочить, и опять двадцать пять.

Во-во и я тоже сразу не вкурил в чем умность по пиду определять процесс, он ведь уникальный, а с пидом как раз и возникали проблемы о которых я писал в СП.

Таким образом (грепать пээс) можно проверять не один процесс. Например, у меня их 5 штук и какие-то зависят от работы сразу нескольких, например, если выполняется процесс get_feeds.php, то ни в коем случае нельзя запускать агрегацию, потому что get_feeds.php делает TRUNCATE таблицы и если в этот момент запустить aggregate.php, то для него не будет рабочих данных.

В общем, щас юзаю Ваш метод, DeepVarvar. Посмотрим что из этого получиться. Но все равно спасибо за грамотные наводки! Курю
 
 Top
esterio
Отправлено: 11 Декабря, 2014 - 02:08:30
Post Id



Активный участник


Покинул форум
Сообщений всего: 5025
Дата рег-ции: Нояб. 2012  
Откуда: Украина, Львов


Помог: 127 раз(а)




nkl
жду результатов. стало интересно посмотреть на танцы с бубном. вдруг и у меня такая же задача когда-то будет. буду знать как решать.

скажу что недавно делал похожую задачу. но у меня не было строго порядка исполнения. использовал впервые gearman и superbisor. только допилил запрет запуска одовременно одного и того же джоба. для етих целей использовал БД с уникальным ИД который генерил сам, ИД который генерил gearman и флаг активно/не активно и тип задачи. если активный таск не позволял запускать еще один такой же. по окончанию джоба апдейтил флаг в 0 (не активно). в конце получилось очень даже ничего, вполне рабочый вариант. но теперь есть боязнь утечек памяти или отвала скрипта в самый не подходящый момент. для этого мне подсказали что нужно время от времени убивать процесы воркеров (когда нету исполнения задач), после супервизор сам запустит новый процесс.

незнаю может мой експириенс набутый всего несколько дней тому назад вам поможет

(Отредактировано автором: 11 Декабря, 2014 - 02:10:18)

 
 Top
nkl
Отправлено: 11 Декабря, 2014 - 06:53:29
Post Id



Посетитель


Покинул форум
Сообщений всего: 305
Дата рег-ции: Янв. 2012  


Помог: 1 раз(а)




Господа это гениально! Вот 2 простых теста, которые доказывают, что register_shutdown_function(), выполняется даже если у вас Allowed memory size или Maximum execution time!
CODE (php):
скопировать код в буфер обмена
  1. <?php
  2.  
  3. ini_set('memory_limit', '1M');
  4. print "Start...\n";
  5. $arr = array();
  6. for($i = 0; $i < 1000000; $i++){
  7.         //$arr[$i] = rand(1000000, 9999999);
  8.         for($j = 0; $j < 1000; $j++){
  9.                 $sum = $i + $j;
  10.         }
  11.         print $sum."\n";
  12. }
  13.  
  14. //var_dump($arr);
  15.  
  16. function shutdownd(){
  17.         print ("The end of script!\n");
  18. }

Вывод:
Цитата:
...
42765
42766
42767
42768
42769
42770
42771
PHP Fatal error: Maximum execution time of 2 seconds exceeded in /home/user/scripts/test_shutdown .php on line 11
The end of script!

И еще один:
PHP:
скопировать код в буфер обмена
  1. <?PHP
  2.  
  3. ini_set('memory_limit', '1M');
  4.  
  5. print "Start...\n";
  6. $arr = array();
  7. for($i = 0; $i < 1000000; $i++){
  8.         $arr[$i] = $rand(1000000, 9999999);
  9. }
  10.  
  11. var_dump($arr);
  12.  
  13. function shutdownd(){
  14.         print ("The end of script!\n");
  15. }

Вывод:
Цитата:
Start...
PHP Fatal error: Allowed memory size of 1048576 bytes exhausted (tried to allocate 32 bytes) in /home/user/scripts/test_shutdown .php on line 10
The end of script!

А с другой стороны, ведь так и должно быть! Ну не может же пых быть настолько убогим, что бы не обрабатывать такие исключительные ситуации. Хотя может и механизм исключений позволяет такие ошибки отлавливать, честно говоря не знаю, но register_shutdown_function() точно позволяет это сделать! Рот до ушей

esterio, у меня машина вчера сломалась, так что и вчера вечером и сегодня утром до работы пехом пёр. И вы знаете, такие гениальные мысли в голову приходят во время обычной ходьбы, не то что при езде за рулем, так что в скором времени (думаю к концу сегодняшнего дня) приведу пример своего решения моей задачи!

(Отредактировано автором: 11 Декабря, 2014 - 06:54:29)

 
 Top
DeepVarvar Супермодератор
Отправлено: 11 Декабря, 2014 - 08:32:59
Post Id



Активный участник


Покинул форум
Сообщений всего: 10377
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




nkl пишет:
register_shutdown_function() точно позволяет это сделать!
Ну вот и все. Найден обход лимитов по памяти на хостинге ))

Заворачиваем себя в шутдаун и спокойно там работаем.
 
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Вопросы новичков »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB