MODx и 500 000 ресурсов Никто не помогает!

Дополнение: pdoTools

Как можно проследить из моих вопросов, с разбором и записью ресурсов я разобрался :)
Распарсиваю данные, пишу их в MODx (MODx на VPS, 128 памяти выделено), получается примерно в пол миллиона результатов, которые пишутся как подресурсы в свои подрубрики, в рубриках. То есть максимум по 200 ресурсов в конечных контейнерах.

Я вписал что вопрос связан с pdoTools, но это не баг, конечно, я понимаю. Просто использую только его для вывода.

На тестовых запусках с 1-5к ресурсов была проблема, что ресурсы создавались, но как будто не прописывались в MODx, то есть в админке они как ресурсы появлялись но на фронте не выводились, а в админке у контекстного меню не появлялось пункта «просмотреть»,
Что бы решить эту проблему, дописал в конец скрипта добавления $modx->cacheManager->refresh(); и так всё заработало.

Но при полноценном запуске, когда создаются все 400-500к ресурсов, похоже что обновление кэша вешается совсем.

В серверном логе ошибок ничего нет, что к MODx бы относилось, в логе MODx 150mb вот такого:
[2016-12-11 06:21:06] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 100) Resource URI aktyoryi/inostrannyie-aktyoryi/camerondallas/bnxvdv9g0ym-new-video-ask-cam-link-in-bio.html already exists for resource id = 100299; skipping duplicate resource URI for resource id = 100399
[2016-12-11 06:21:06] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 100) Resource URI aktyoryi/inostrannyie-aktyoryi/camerondallas/bnuolscgiem-happy-birthday-beautiful-ginabina77.html already exists for resource id = 100300; skipping duplicate resource URI for resource id = 100400
[2016-12-11 06:21:06] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 100) Resource URI aktyoryi/inostrannyie-aktyoryi/camerondallas/bnr8ibuafbq-twitter-camerondallas.html already exists for resource id = 100301; skipping duplicate resource URI for resource id = 100401
[2016-12-11 06:21:06] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 100) Resource URI aktyoryi/inostrannyie-aktyoryi/camerondallas/bnqdxagglvs-coming-soon-netflix.html already exists for resource id = 100302; skipping duplicate resource URI for resource id = 100402
[2016-12-11 06:21:06] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 100) Resource URI aktyoryi/inostrannyie-aktyoryi/camerondallas/bnjgw91gjom-smile-(.html already exists for resource id = 100303; skipping duplicate resource URI for resource id = 100403
Это же выдаёт консоль при попытке обновления кэша из админки.

Информация по настроке и версии PHP тут starsagram.ru/ph.php

Переписать всё на чистом php и со своими таблицами вариант крайний и не хотелось бы его касаться.
В общем прошу помощи, надеюсь подскажите направление действий.

upd. Выложу ещё как зписываются ресурсы:
$finally = function($new_medias)use(&$insta_user,&$account){
        $insta_user->saveState();
        State::getInstance()->users_checked++;
        State::getInstance()->save();
        if(empty($new_medias))
            return;
        global $has_new_media;
        $has_new_media = true;
        global $modx;
        $resource2 = $modx->getObject('modResource', ['pagetitle'=>$account['resource_name']]);
        if(!$resource2){
            $parent = $modx->getObject('modResource', ['id'=>$account['mainresource_id']]);
            if($parent){
                $resource2 = $modx->newObject('modDocument');
                $resource2->set('parent',$parent->get('id'));
                $resource2->set('pagetitle',$account['resource_name']);
                $resource2->set('longtitle','');
                $resource2->set('alias',$account['username']);
                $resource2->set('description',$account['mainresource_descr']);
                $resource2->set('template',  Settings::$template2);
                $resource2->set('published','1');
                $resource2->set('isfolder','1');
                $resource2->setContent('');
                $resource2->save();

                $resource2->setTVValue('akaunt', $account['username']);
            }
        }
        if($resource2){
            $resource2->setTVValue('avatar', $new_medias[0]->avatar);
            foreach($new_medias as $new_media){
                    $resource3 = $modx->newObject('modDocument');
                    $resource3->set('parent',$resource2->get('id'));
                    $caption = '';

                    if($new_media->caption){
                        $caption = Utils::removeEmoji(trim($caption));
                    }
                    
                    if(!$caption)
                        $caption = 'Запись от '.date('Y-m-d');
                    if(mb_strlen($caption, 'utf8mb4')>100) 
                    $caption = mb_substr ($caption, 0, 100);
                 
                    if(preg_match('#/([^/]+)/?$#sui',$new_media->link,$matches)){
                        $resource3->set('alias',$matches[1]."-".$caption);
                    }
                     
                    $resource3->set('pagetitle',$caption);
                    $resource3->set('longtitle','');
                    $resource3->set('description','');
                    $resource3->set('template',  Settings::$template3);
                    $resource3->set('published','1');
                    $resource3->setContent($content);
                    $resource3->save();

                    $resource3->setTVValue('akaunt', $account['username']);
                    $resource3->setTVValue('avatar', $new_medias[0]->avatar);
            }           
        }
    };

ну и после отработки всех циклов записи
 $modx->cacheManager->refresh();
11 декабря 2016, 10:00    Михаил   G+  
3    794 0

Комментарии (30)

  1. Григорий Коленько 11 декабря 2016, 10:30 # 0
    Так у тебя в логе пишет, что дублируются алиасы ресурсов
    1. Михаил 11 декабря 2016, 10:32 # 0
      да, я вижу, но не понимаю откуда берётся. После обновления кэша на малом количестве записей ошибка пропадала.
      1. Михаил 11 декабря 2016, 10:39 # 0
        Ну и при создании, алиасы не могут повторяться, по тому что генерятся на основе уникальных записей. По коду проверил, два раза запись тоже не происходит.
        1. Григорий Коленько 11 декабря 2016, 10:47 # 0
          У тебя айди ресурсов написаны. Посмотри что ч ними нетак
          1. Михаил 11 декабря 2016, 11:03 # 0
            В том то и дело что алиас там уникальный prntscr.com/dhz7zh подчёркнутая часть она вообще из адреса инсты prntscr.com/dhz8ck, ресурс открывается, из него на фронт переходит, там он тоже есть, но modx как бы не в курсе что он есть, так как в контекстном меню не выводит «посмотреть» prntscr.com/dhz8z0
            1. Михаил 11 декабря 2016, 11:17 # 0
              О, точно иногда по 2 ресурса создаётся одинаковых, вероятно из за того что скрипт как то не корректно проверяет, но в любом случае на тестовых запусках по 1000 ресурсов, это не мешало особо
              1. but1head 11 декабря 2016, 18:04 # 0
                $resource2->set('alias',$account['username'])
                В логах видно что алиас дублируется
                1. Михаил 11 декабря 2016, 18:55 # 0
                  Эта строчка записывает алиас для контейнеров в которых создаются ресурсы среди которых уже алиасы дублируются.
                  Кстати на каком моменте они дублируются, я так и не нашёл. Но это вообще не должно мешать обновлению кеша, он видимо не обновляется из за общего количества ресурсов.
                  1. but1head 11 декабря 2016, 18:59 # 0
                    В логах ясно видно что 100299 и 100399 имеют одинаковую ссылку (алиас) в этом и проблема, кэш тут не причем.
        2. Михаил 11 декабря 2016, 10:47 # 0
          добавил функцию как записываю ресурс
        3. Михаил 12 декабря 2016, 15:52 # +1
          ok, отключаю чпу совсем, провожу наполнение заново, тоже самое, на 5000 ресурсов всё отлично, на 500 000 админка падает, даже дерево не показывает, хотя там всё разбито на подкаталоги, максимум по 200 ресурсов в контейнерах. Всё это крутится на vds.
          Скажите, стандартные механизмы MODx в принципе не рассчитаны на такую нагрузку и надо делать свою таблицу, свои выборки т.п. или дело в чём то другом?
          1. but1head 12 декабря 2016, 17:03 # 0
            ставить что-то вроде collections, категории = коллекции, чтоб страницы не грузились в админку. Или написать свой компонент на modExtra.
            1. Михаил 12 декабря 2016, 17:42 # 0
              Ну там не только админка падает… морда тоже падает, а на ней вызов только pdoMenu с level=1
              Но про свой компонент я понял… но не скоро осилю видимо.
            2. Михаил 13 декабря 2016, 18:48 # 0
              Тут допустил не точность. Если отключить ЧПУ, наполнить и не включать, то всё прекрасно работает. Ресурсов окло 500к.
            3. Алексей Хребтов 12 декабря 2016, 19:22 # 0
              Когда заливаете тестовые данные на 5000 ресов, то делаете на этом же сервере?
              Или локально? Конфигурация ПО совпадает?
              1. Михаил 13 декабря 2016, 04:24 # 0
                Да, на том же сервере.
              2. Михаил 13 декабря 2016, 05:28 # 0
                Вот как ещё проверил:
                Отключаю дружественные урл, наполняю бд и оно работает. Иду, включаю д.урл и всё, админка падает, ошибки такие:
                [2016-12-13 01:17:23] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 680) Error caching time of next auto publishing event
                [2016-12-13 01:17:44] (ERROR @ /var/www/www-root/data/www/starsagram.ru/core/model/modx/modcachemanager.class.php : 166) Could not cache context settings for web.
                
                Получается что механизм кеширования не может прожевать такое количество ресурсов?
                Что делать, отказаться от д.урл? Может я в скрипте как то не так новые ресурсы создаю?
                1. Николай Ланец 13 декабря 2016, 05:57 # +2
                  Отключение ЧПУ не спасет. Читайте очень внимательно этот материал: modxclub.ru/blog/139.html
                  1. Михаил 13 декабря 2016, 19:25 # 0
                    Вообще спасло немного… я заливаю дамп базы без ресурсов, отключаю чпу совсем, наполняю ресурсами и всё работает, ресурсы выводятся, меню генеряться, не быстро правда )
                    <!-- 
                    	total time: 6.7186 s
                    	query time: 0.0000 s
                    	queries: 0
                    -->
                    Но если включить чпу то всё упадёт, выключить уже не получится. Скажите пожалуйста, ваш модифицированный код в методе modContext_mysql::getResourceCacheMapStmt() из примра, может решить эту проблему?

                    И что ещё можно сделать с оптимизацией этого всего, что бы так не грузить сильно сервер?
                    1. Николай Ланец 14 декабря 2016, 11:23 # 0
                      Михаил, с этим проблем куча. Это тот случай, когда поправляя одно, будет ломаться другое. Когда вы включаете ЧПУ, MODX пытается все за раз запихнуть в кеш (в вашем случае это 500к документов, что, мягко говоря, для него слишком много). Из-за этого кеш может даже сохраниться битым и сайт начнет вообще фатальную ошибку выдавать. В таких случаях я не знаю другого решения, кроме как cacheOptimizer. Но, у вас при включении ЧПУ, но отсутствии карты ресурсов в кеше контекста, многие вещи будут просто не работать (включая получение документа по УРЛу). Я в свое время был вынужден такое делать при создании сайта на 150к документов, и пришлось несколько переписывать modRequest, чтобы все работало как надо. Все это требует очень много телодвижений. Поэтому мне нечего вам дельного посоветовать. Или переводить все эти документы на отдельные таблицы, писать свой роутер, интерфейсы и т.п., или вообще сворачивать проект.
                      1. Дмитрий Вершинин 14 декабря 2016, 15:49 # 0
                        Николай, а какое по вашему мнению предельное количество ресурсов, с которым MODX работает из коробки?
                        1. Николай Ланец 14 декабря 2016, 16:05 # 0
                          Без тюнинга в пределах 20-30 тысяч на среднем хостинге. На шустром ~50к. Встречал такие площадки, на которых и 10к уже очень серьезно дает о себе знать, но это совсем деревянные.
                2. Василий Наумкин 14 декабря 2016, 12:43 # +3
                  500 000 страниц сайта — это нормально. А вот 500 000 ресурсов — совершенно нет, MODX к такому не готов.

                  Разница в том, что ресурсы нужны для разделов сайта, служебных страниц и всего такого. Если же сайт продаёт полмиллиона товаров или содержит объявления — нужно это выносить в отдельные таблицы, с нужными колонками и индексами.

                  Например, вот я делал vrmedia.tv. Ресурсов в дереве там меньше 50, а фоторепортажей и картинок многие тысячи. Всё летает, лайкается, добавляется в избранное — и хранится в отдельных таблицах.

                  В таком направлении и нужно двигаться, используя MODX как удобную обёртку для своих данных.
                  1. Михаил 14 декабря 2016, 16:09 # 0
                    Эх… я похоже не осилю отдельные таблицы… Василий, а если для этих целей ваш Tickets использовать? Он тоже не рассчитан на такое количество страниц?
                    1. Василий Наумкин 14 декабря 2016, 16:33 # 0
                      Так он на тех же ресурсах работает — так что нет.
                      1. Василий Столейков 15 декабря 2016, 09:37 # +1
                        Если ты осилил этот PHP код, то и отдельные таблицы осилишь.
                        У меня на 200 000+ ресурсах такая же проблема была. Пришлось разбить на несколько (у меня 7) таблиц по разделам. По сути поля могут в точности повторять поле из таблицы modx_site_content.

                        Создай столько таблиц, сколько у тебя крупных разделов (например modx_site_content_1 и т.д.). И расфасовывай уже страницы по этим таблицам в зависимости от раздела.

                        Дальше можешь воспользоваться компонентом VirtualPage, чтобы создать в этих разделах отдельные адреса страниц. Выборку можешь сделать по конкретно взятой таблице категории через простой PHP, например:
                        $q = $modx->prepare("SELECT * FROM ".$modx->config['table_prefix']."site_content_1 LIMIT 50");
                        $q->execute();
                        $r = $q->fetchAll(PDO::FETCH_ASSOC);
                        foreach($r as $row){
                            $id = $row['id'];
                            print_r($row);
                        }
                        
                        Если же нужна пагинация и все дела, то сделай на основе этих таблиц с помощью UICMPGenerator модели и подключай свой класс таблицы в pdoPage.

                        И при таком раскладе Василий правду сказал — у тебя в админке останутся только ресурсы категорий (по ним сможешь делать менюшки на pdoMenu и т.д.

                        Также скорее всего прийдётся создать несколько отдельных страниц с XML-картами этих разделов и скормить их robots.txt и Яндексу.
                        1. Василий Наумкин 15 декабря 2016, 11:32 # +1
                          Пришлось разбить на несколько (у меня 7) таблиц по разделам. По сути поля могут в точности повторять поле из таблицы modx_site_content.
                          Несколько одинаковых таблиц точно делать не стоит. Задача — вынести данные из modx_site_context, чтобы MODX не пытался их кэшировать в карту ресурсов, и всё.

                          А в своей таблице могут быть и миллионы записей — тут уже ограничения могут быть только у MySQL, а не сайта.

                          Разные таблицы нужны только для разных сущностей. Например, фоторепортажи и лайки для них — 2 разные таблицы, а распихивать 200 000 фоторепортажей по 7 таблицам бессмысленно.
                          1. Василий Столейков 15 декабря 2016, 11:38 # 0
                            Ок, согласен. Но если все 500 000 записей будут запихнуты в одну таблицу, то при выборке или подсчёте количества по разным критериям или при пагинации могут быть дикие тормоза (по крайней мере у меня были).

                            Мне кажется оба варианта имеют право на жизнь и оба решают основную проблему — разгрузку основной таблицы modx_site_content…

                            P.S. Правда и таблицы у меня были с огромным количеством полей и информации (намного больше чем у родной таблицы) — это тоже могло повлиять на вес таблицы и на тормоза при выборке.
                            1. Василий Наумкин 15 декабря 2016, 11:49 # +3
                              А это уже решается правильными индексами. Ну и, возможно, огромное количество полей стоило вынести в отдельную таблицу.

                              У меня прямо сейчас есть внутренний сайт организации с миллионами строк в таблицах — и всё хорошо работает.
                              Правильная организация базы данных — целая наука, этому годами учатся. Но, это уже лирика, я просто высказался против нескольких одинаковых таблиц.
                              1. Василий Столейков 15 декабря 2016, 11:52 # 0
                                Очень логично, спасибо за полезные мысли!
                                Возьму их на вооружение на будущее!
                    Вы должны авторизоваться, чтобы оставлять комментарии.