我使用的是Laravel 5.1。
队列用于在多个系统之间获取/同步数据。
我使用数据库驱动程序,3个"artisan queue:work --daemon“进程一直在运行。
作业由系统用户和调度程序(cron)分派。使用三个队列来确定作业的优先级。
一切似乎都运行得很好--作业表中充满了记录,系统会处理这些记录,并删除已完成的记录。
然而,在一段时间后,锁定问题开始干扰:
SQLSTATE40001:序列化失败:尝试获取锁时发现1213死锁;请尝试重新启动事务
和
'RuntimeException‘并显示消息’Can‘with PDO instance Can transaction.’
和
SQLSTATEHY000:常规错误: 1205锁定等待超时;请尝试重新启动事务
我还没有尝试使用其他队列驱动程序。不过我真的很想继续使用数据库。引擎是InnoDB,作业表有默认的结构和索引。
有没有办法解决这个问题?你的想法是什么?
值得一提的是,我在作业类中调用DB::reconnect(),因为队列工作进程是作为守护进程运行的。
正如人们所预期的那样,作业使用DispatchesJobs特征进行分派。我不会以任何其他方式干扰队列算法。
发布于 2016-01-13 12:13:07
这可能不是答案,而是一些信息。
在使用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最后一行
如果您的事务中有很多影响并发和性能的间隙锁,您可以通过两种不同的方式禁用它们:
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.发布于 2019-03-12 23:39:07
我在Laravel上编写队列管理系统,我有多个作业,有多个用户,我应该发送电子邮件。我正在运行许多工人与主管和避免多个电子邮件发送给同一个用户,我写了这段代码。希望它能帮助解决这个问题的人
DB::transaction(function () use ($job) {
if (!count($job->jobUsers()->sharedLock()->get())) { // to share reading ability btw multiple workers
Log::info('There is no user in this job');
$job->status = Job::STATUS_FINISHED;
$job->save();
return;
}
foreach ($job->jobUsers as $jobUser) {
Log::info($jobUser->user_id);
JobUser::where('job_id', $jobUser->job_id)
->where('user_id', $jobUser->user_id)
->lockForUpdate() // exclusive lock
->update(['status' => JobUser::STATUS_SENT]);
}
});https://stackoverflow.com/questions/32475853
复制相似问题