Как я могу ускорить функцию node_save () в drupal?

9

У меня много проблем с неэффективностью node_save (). Но спасает ли узел мою проблему? В конечном итоге это то, что я пытаюсь выяснить.

Я создал цикл с 100 000 итераций. Я создал минимум для того, чтобы объект узла был действительным и сохранялся правильно. Вот код сохранения узла:

$node = new stdClass();
        $node->type = "test_page";

        node_object_prepare($node);

        $node->uid = 1;
        $node->title = $node_title;
        $node->status = 1;
        $node->language = LANGUAGE_NONE;
        if($node = node_submit($node)){
            node_save($node);
}

Вот результаты:

100 000 узлов были сохранены, каждый с помощью node_save (). Это заняло 5196,22 секунды. Это только 19 экономит секунду.

По меньшей мере, это неприемлемо, особенно когда этот человек получает около 1200 отдельных запросов на вставку в секунду , а этот человек получает 25 000 вставок в секунду .

Итак, что здесь происходит? Где узкое место? Это с функцией node_save () и как она разработана?

Может ли это быть мое оборудование? Мое оборудование - это сервер разработки, на котором нет никого, кроме меня - двухъядерный Intel, 3Ghz, Ubuntu 12.04 с 16 гигабайтами оперативной памяти.

В то время как цикл работает, мой ресурс использует: MySQL 27% CPU, 6M RAM; PHP 22% CPU 2M RAM.

Моя конфигурация mysql была сделана мастером Percona .

Mysql говорит, что если загрузка моего процессора ниже 70%, моя проблема связана с диском . Конечно, у меня есть только пробег мельницы WD Caviar 7200 об / мин, но я должен получить более 19 вставок в секунду с этим, я надеюсь!

Не так давно я писал о сохранении 30 000 узлов в день . Однако, чтобы было ясно, этот узел не имеет никакого отношения к каким-либо внешним силам. Это просто тест, чтобы узнать, как увеличить скорость вызовов node_save ().

На самом деле мне нужно каждую минуту получать 30 000 элементов в базу данных с помощью node_save. Если сохранение узла не является опцией, мне интересно, могу ли я написать свою собственную API-функцию drupal "node_batch_save ()" или что-то, что использует способность mysql выполнять массовые вставки с помощью запроса INSERT . Мысли о том, как подойти к этому?

blue928
источник
2
Существует большая разница между производительностью необработанной вставки и тем, что будет делать node_save. С одной стороны, node_save выполняет серию операций чтения и записи. Но нет смысла обсуждать возможные узкие места и оптимизации без дополнительных данных.
Альфред Армстронг
Вам нужно подумать, почему вы используете Drupal таким образом для своих целей. Если вы просто хотите собрать много данных в виде плоской таблицы и отобразить их с помощью Drupal, вы можете вообще обойтись без Drupal при написании и использовать собственный модуль для интеграции данных с использованием Views и т. Д.
Альфред Армстронг,
Я сомневаюсь, что горлышко бутылки находится на стороне базы данных. Узел save делает много вещей в фоновом режиме: он вызывает несколько перехватчиков (hook_node_presave, hook_entity_presave, hook_node_insert, hook_entity_insert и т. Д.), Каждый из которых может вызывать любое количество модулей. Кроме того, node_save перестроит разрешения для этого узла и очистит кэш для этого узла ...
Алиса Хитон,
@AlfredArmstrong Я создаю узлы на основе данных, которые находятся в другой базе данных. Я формирую данные в соответствии с правильным типом контента drupal и сохраняю его node_save. Мои клиенты в основном университеты, желающие перейти на drupal. Для них нередко иметь от 200 000 до 1 000 000 узлов (содержимое сайтов депов, записи студентов и преподавателей и т. Д.), Которые они хотели бы перенести после десятилетия использования своих собственных в веб-решениях. Я читаю это, что обнадеживает, но все же менее желательный подход. evolvingweb.ca/story/…
blue928
.. так что я бы предпочел остаться как можно более дружелюбным. Использование сохранения узла с таким большим количеством данных обеспечивает целостность. Если я не могу заставить это работать, я хочу проявить творческий подход.
blue928

Ответы:

10

Вы никогда не получите 30 000 вставок в минуту, используя node_save. Ни за что.

ВСТАВКА быстрая, потому что это все, что она делает. Узел save выполняет несколько вставок (основная таблица, таблица редакций, таблица для каждого поля), очищает любые кэши объектов и запускает перехватчики. Крючки являются сложной частью. Если у вас есть много модулей contrib (или даже одного, который плохо себя ведет), которые действительно могут снизить производительность, особенно если автор не учел вариант использования «Я экономлю тонну узлов сразу». Например, мне пришлось добавить это в мой класс Migrate:

  public function processImport(array $options = array()) {
    parent::processImport($options = array());
    // Do not force menu rebuilding. Otherwise pathauto will try to rebuild
    // in each node_save() invocation.
    variable_set('menu_rebuild_needed', FALSE);
  }

С другой стороны, если вы напишите пользовательскую функцию сохранения, которая не вызывает хуков, вы подвергаетесь явной опасности получения противоречивых данных в состоянии, неожиданном для системы. Я бы никогда не рекомендовал это делать. Запустите xhprof и посмотрите, что происходит.

Боян Живанович
источник
Некоторые из модулей миграции существуют, как они заканчивают узлами массового сохранения? Я имею в виду, в конце концов, все сводится к утверждению INSERT, верно? Как ваш класс миграции в конечном итоге вставляет из «источника» в «цель», когда не используется сохранение узла, но все еще необходимо поддерживать целостность данных между таблицами?
blue928,
Все модули миграции, с которыми я сталкивался, используют node_save.
Альфред Армстронг
1
@ blue928 Он говорит , что он делает использование node_save(), но добавляет некоторый код смягчать известные проблемы , которые могут быть вызваны, например Pathauto восстановления кэша меню после каждого узла экономии
Clive
ах, понятно Боян, есть ли твой код в модуле или онлайн, где я мог видеть, как ты справлялся с узкими местами, такими как path auto? Хорошая идея с xhprof. Я проверю это.
blue928
5

Прежде всего, установите XCache / APC (для PHP <5.5) и настройте memcached для Drupal.

Затем вы можете оптимизировать конфигурацию MySQL для сложных запросов, используя скрипт mysqltuner, доступный по адресу: http://mysqltuner.pl

Например

# performance tweaks (adjusted based on mysqltuner.pl)
query_cache_size = 32M
query_cache_limit = 256M
join_buffer_size = 32M
key_buffer = 8M
max_allowed_packet = 32M
table_cache = 512
sort_buffer_size = 1M
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 1M
myisam_sort_buffer_size = 8M

# When making adjustments, make tmp_table_size/max_heap_table_size equal
tmp_table_size = 16M
max_heap_table_size = 16M

thread_cache_size = 4

Другие предложения:

  • отключить ненужные модули (например, Devel , основной модуль ведения журнала базы данных и т. д.),
  • обновить ваш PHP до последней или более поздней ветки,
  • перекомпилируйте ваш PHP для 64-битной или более высокой архитектуры в зависимости от вашего процессора,
  • используйте более быстрое устройство хранения для ваших файлов базы данных или всей среды LAMP (например, SSD или файловую систему на основе памяти ),
  • использовать PHP-отладчик или профилировщик, чтобы найти любое узкое место в производительности (например, XDebug Profiler , DTrace или NuSphere PhpED PHP Profiler ),
  • запустите некоторую трудоемкую команду drush в инструменте профилирования gprof , чтобы вы могли также найти узкое место в производительности
kenorb
источник
1
Настройка MySQL, кажется, имеет большое значение. Я перешел с 80 node_saves в минуту до 700, просто следуя советам mysqltuner.pl.
Джон Макколлум