Взаимоблокировки Magento

Я использую Magento 1.7.0.2 Community Edition и столкнулся с большой проблемой - взаимоблокировками и ошибками "Превышено время ожидания блокировки". Проблема существует во время выполнения определенных задач CRON

  • Импорт/обновление товаров (размеры, цвета, производители). Существует около 5000 продуктов, но в 90% скрипт получает ошибки «Превышено время ожидания блокировки» или ошибку взаимоблокировки. Скрипт разработан с использованием руководств Magento и отлично работает, если никакие другие процессы не запущены. Например, если работает переиндексация, мы обязательно получим ошибку. Похоже, это из-за блокировки таблицы
  • В некоторых случаях Magento устанавливает блокировку чтения. Я уже прочитал несколько тем об этом, и единственным правильным решением является изменение функции /lib/Zend/Db/Statement/Pdo.php _execute. Поскольку мы с нетерпением ждем обновления Magento до последней стабильной версии, мы не можем позволить себе изменение файлов ядра.

Итак, мой вопрос - есть ли способ избежать этого (будь то на уровне PHP, MySQL или сервера (мы используем nginx))?


person werd    schedule 09.11.2012    source источник
comment
Почему бы не разделить количество продуктов на более мелкие куски?   -  person Rick Kuipers    schedule 09.11.2012
comment
Я уже думал об этом, но с этим также есть проблема, потому что продукты извлекаются через стороннюю службу Soap, и они не предоставляют более мелкие фрагменты. Конечно, мы можем разделить его на нашу сторону, но в любом случае этот процесс обновления должен выполняться почти вечно, чтобы обеспечить самые последние данные из внешнего склада продуктов.   -  person werd    schedule 09.11.2012
comment
Кроме того, разделение данных на более мелкие фрагменты даст тот же результат, если мы создадим дочерние процессы, используя механизм fork. В этом случае каждый дочерний процесс будет записывать/читать одни и те же таблицы и заканчиваться ошибкой.   -  person werd    schedule 09.11.2012
comment
Вы получите тупик, если переиндексируете одновременно с импортом. Оба процесса работают с одними и теми же файлами, а это означает, что очень важно выбрать время, чтобы они не наступали друг другу на пятки.   -  person Fiasco Labs    schedule 09.11.2012
comment
После каждого импорта/обновления продукта я вызываю переиндексацию для этого конкретного продукта. Полная переиндексация производится только один раз в сутки. Может ли это вызвать проблему?   -  person werd    schedule 12.11.2012


Ответы (5)


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

Чтобы решить эту проблему, мне пришлось разместить запросы к базе данных в SERIALIZABLE. транзакций, где это возможно, например:

$adapter = Mage::getModel('core/resource')->getConnection('core_write');
// Commit any existing transactions (use with caution!)
if ($adapter->getTransactionLevel > 0) {
    $adapter->commit();
}
$adapter->query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
$product->save(); // etc

Пример транзакции:

$adapter = Mage::getModel('core/resource')->getConnection('core_write');
// Commit any existing transactions (use with caution!)
if ($adapter->getTransactionLevel > 0) {
    $adapter->commit();
}
$adapter->query('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
$adapter->beginTransaction();
try {
    $adapter->query(/* SQL goes here */);
    $adapter->commit();
} catch (Exception $e) {
    // Rollback on fail always
    $adapter->rollBack();
    throw $e;
}

Если вам потребуется дополнительная помощь в этом, не стесняйтесь, дайте мне знать.

person james    schedule 12.11.2012
comment
Применяется ли это при использовании Mage::getModel() вместо простых запросов? - person werd; 13.11.2012
comment
Magento использует транзакции за кулисами (при сохранении ресурса конкретной модели). Вы можете попробовать первый вариант (установить уровень изоляции транзакций), а затем сохранять/редактировать модели по своему усмотрению. - person james; 13.11.2012
comment
Удар. Это удивительное исправление. Это буквально так же просто, как кажется — возьмите адаптер и установите уровень изоляции выше вашего сохранения. Это исправило более года головной боли для моей команды! +1 - person philwinkle; 13.12.2012
comment
Заинтересованы во внедрении этого решения для крупного магазина Magento. Не могли бы вы посоветовать, где нам нужно это реализовать? Заранее спасибо. - person zigojacko; 22.08.2013
comment
@GeoffJackson philwinkle упаковал это в расширение: github.com/philwinkle/Philwinkle_DeadlockRetry. Вы также можете установить уровень изоляции транзакций в /etc/my.cnf - person james; 22.08.2013
comment
Это здорово, спасибо, ребята. Мы только что установили расширение, чтобы проверить. :) - person zigojacko; 22.08.2013
comment
Согласно Википедии, this isolation level specifies that all transactions occur in a completely isolated fashion; i.e., as if all transactions in the system had executed serially, one after the other. . Что, в свою очередь, означает, что производительность БД будет значительно снижена, я прав? - person srgb; 08.05.2014
comment
This is necessary because “phantom rows” must be blocked for MySQL replication and recovery to work. Делая это, убедитесь, что регулярно и ежедневно делаете резервные копии БД, потому что, если она повреждена, восстановление может оказаться трудным. Проблема связана с самой MySQL, а не с Magento. stackoverflow.com /questions/6269471/ Но будьте очень осторожны с побочными эффектами: ovaistariq.net/597/ - person B00MER; 05.06.2014

У нас была аналогичная проблема с появлением взаимоблокировок несколько раз в день, когда клиенты пытались что-то добавить в свою корзину. Наши тоже, похоже, были связаны с обновляемым в то время индексом (скорее всего, с переиндексацией таблицы каталога). Единственное, что, наконец, решило проблему для нас, — это реализовать асинхронную переиндексацию (в итоге мы купили расширение).

person fr0x    schedule 24.05.2013
comment
Да, мы тоже купили - person werd; 31.05.2013
comment
НО даже это может создать новую проблему: они часто поставляются с валидаторами, которые обнаруживают изменения и даже затем переиндексируют: в этом случае (часто позже) новый клиент может столкнуться с той же проблемой. - person snh_nl; 09.01.2018

мы столкнулись с этой проблемой, пытаясь сохранить продукты параллельно.

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

решение, к которому мы пришли, заключалось в том, чтобы включить индексатор в транзакцию и повторить транзакцию, которая оказалась в тупике. однако это не идеальное решение, это лучшее, что мы могли придумать, и оно работает в 99% случаев.

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

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

person greenone83    schedule 09.10.2013

Вот отличное решение с открытым исходным кодом — https://github.com/AOEpeople/Aoe_DbRetry.

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

person FireBear    schedule 05.04.2018

Я переключаю режим индексирования на РУЧНОЙ перед импортом с помощью сценариев CRON.

$indexCollection = Mage::getSingleton('index/indexer')->getProcessesCollection(); 
foreach ($indexCollection as $process) {
    $process->setMode(Mage_Index_Model_Process::MODE_MANUAL)->save();
    //$process->setMode(Mage_Index_Model_Process::MODE_REAL_TIME)->save();
}
person Kurdt94    schedule 08.12.2015