如何避免使用Laravel队列时的作业DB表锁问题?

kmpatx3s  于 2023-05-30  发布在  其他
关注(0)|答案(3)|浏览(311)

我用的是Laravel 5.1。
队列用于多个系统之间的数据获取/同步。
我使用的是数据库驱动程序,3个“artisan queue:work --daemon”进程一直在运行。
作业由系统用户和调度程序(cron)调度。使用三个队列来确定作业的优先级。
一切似乎都运行得很好--作业表中充满了记录,系统会处理它们并删除已完成的记录。
然而,一段时间后,锁定问题开始干扰:
SQLSTATE[40001]:序列化失败:1213尝试获取锁时发现死锁;尝试重新启动事务

“RuntimeException”,消息为“在事务内无法交换PDO示例”。

SQLSTATE[HY000]:一般错误:1205锁定等待超时;尝试重新启动事务
我还没有尝试使用其他队列驱动程序。我真的很喜欢数据库。引擎是InnoDB,作业表具有默认结构和索引。
有没有办法解决这个问题?你的想法是什么?
值得一提的是,我在作业类中调用了DB::reconnect(),因为队列工作进程是作为守护进程运行的。
正如人们所期望的那样,使用DispatchesJobs trait分派作业。我不会以任何其他方式干扰队列算法。

ssm49v7z

ssm49v7z1#

这可能不是答案,而是一些信息。
当使用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.

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

deikduxw

deikduxw2#

我在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]);
            }

        });
j2qf4p5b

j2qf4p5b3#

在管理程序配置文件中,使numprocs = 1,因为“205锁定等待超时已超过;尝试重新启动”此错误只发生在多个队列工作者在同一表或表的同一行上执行同一任务时。这将在表中创建死锁

相关问题