Подтвердить что ты не робот

Как избежать проблем с блокировкой таблиц базы данных при использовании очередей Laravel?

Я использую Laravel 5.1.

Очереди используются для сбора/синхронизации данных между несколькими системами.

Я использую драйвер базы данных, все три процесса "workisan queue: work --daemon" работают постоянно.

Работы отправляются как пользователями системы, так и планировщиком (cron). Для приоритизации заданий используются три очереди.

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

Однако через некоторое время проблемы блокировки начинают мешать:

SQLSTATE [40001]: сбой последовательной обработки: 1213. пытаясь получить блокировку; попробуйте перезапустить транзакцию

и

"RuntimeException" с сообщением "Невозможно заменить PDO-экземпляр в то время как внутри сделка.

и

SQLSTATE [HY000]: общая ошибка: 1205 превышено время ожидания блокировки; пытаться перезагрузка транзакции

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

Есть ли способ решить эту проблему? Каковы ваши мысли?

Возможно, стоит упомянуть, что я вызываю DB::reconnect() внутри моих классов заданий, так как рабочие очереди работают как демоны.

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

4b9b3361

Ответ 1

Это может быть не ответ, а какая-то информация.

При использовании операторов SELECT ... FOR UPDATE вы можете наблюдать за конфликтом блокировки (мертвые блокировки и т.д.).

select … for update where x <= y

его сканирование диапазона с < = база данных блокирует все строки <= y, включая любые пробелы поэтому, если у вас есть строки с y, как это: 1, 3, 5 он блокирует даже пустое пространство между 1 и 3 в индексе его названная блокировка запирания

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

SHOW ENGINE INNODB STATUS;

---TRANSACTION 72C, ACTIVE 755 sec
4 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 1
MySQL thread id 3, OS thread handle 0x7f84a78ba700, query id 163 localhost msandbox
TABLE LOCK table test.t trx id 72C lock mode IX
RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X
RECORD LOCKS space id 19 page no 3 n bits 80 index GEN_CLUST_INDEX of table test.t trx id 72C lock_mode X locks rec but not gap
RECORD LOCKS space id 19 page no 4 n bits 80 index age of table test.t trx id 72C lock_mode X locks gap before rec

последняя строка

Если у вас много блокировок в транзакциях, влияющих на concurrency, и производительность вы можете отключить их двумя способами:

1- Change the ISOLATION level to READ COMMITTED. In this isolation level, it is normal and expected that query results can change during a transaction, so there is no need to create locks to prevent that from happening.

2- innodb_locks_unsafe_for_binlog = 1. Disables the gap locks except for foreign-key constraint checking or duplicate-key checking.

https://www.percona.com/blog/2012/03/27/innodbs-gap-locks/

Ответ 2

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

* Это не вариант, если таблицы имеют внешние ключи, и вы полагаетесь на такие вещи, как каскадные удаления и обновления, которые находятся только в innoDB