在我的rails项目中,我使用sidekiq处理耗时的任务,但是在sidekiq中记录错误:
ActiveRecord::StatementInvalid: Mysql2::Error: Lock wait timeout exceeded; try restarting transaction: UPDATE `marker_layers` SET `show_fields` = 'title,desc', `sort_col` = 'title,desc', `updated_at` = '2016-05-17 07:36:02' WHERE `marker_layers`.`id` = 16021210
Processor: iZ23edse84Z:29310
# Options here can still be overridden by cmd line args.
# setsid sidekiq -d -C config/sidekiq.yml -e production
---
:concurrency: 5
:pidfile: tmp/pids/sidekiq.pid
:logfile: log/sidekiq.log
staging:
:concurrency: 10
production:
:concurrency: 40
:queues:
- ['critical', 3]
- ['default', 2]
- ['low', 1]
数据库.yml
production:
adapter: mysql2
encoding: utf8mb4
collation: utf8mb4_bin
reconnect: false
database: database_name
pool: 48
username: password
password: password
host: locahost
发生此错误的原因是不同的工作人员尝试修改同一资源时事务超时,基本上是数据库死锁。
如果您像
SomeModel.transaction { SomeModel.task_that_takes_too_much_time }
那样显式使用事务,或者使用修改记录的普通 ActiveRecord 方法,就会发生这种情况,因为所有内容都包含在事务中。
我能给你的唯一建议是探索让你的工人独特的替代方案,比如使用https://github.com/mhenrixon/sidekiq-unique-jobs并使你的工作使用
.perform_in
。
这意味着操作的记录已经被另一个慢SQL锁定,并且等待了很长时间。
也许您的代码中有很多长事务。
检查代码,优化慢 SQL 并拆分长事务。
希望这对您有帮助。
当数据库大小增长并且您显式执行大量事务时,可能会发生这种情况,可能其他某个线程在某些记录上持有记录锁的时间太长,并且您的线程超时。
我使用的一个解决方案是延长等待超时。
通过终端登录MySQL并运行它。
SET GLOBAL innodb_lock_wait_timeout = 28800;
您可以做的另一件事是强制解锁 MySQL 中锁定的表:
像这样破坏锁通常会导致数据库中的原子性无法在导致锁的 sql 语句上强制执行。
这是一个黑客行为。正确的解决方案是修复导致锁定的应用程序。