【发布时间】:2019-10-14 01:10:23
【问题描述】:
当delayed_jobs 表开始在几百个之上增长时,工作人员的性能开始呈指数级下降。
【问题讨论】:
标签: ruby delayed-job
当delayed_jobs 表开始在几百个之上增长时,工作人员的性能开始呈指数级下降。
【问题讨论】:
标签: ruby delayed-job
我已经多次在这个问题上苦苦挣扎,所以我将我的发现公开给未来的新手,让他们面对这个噩梦。
DelayedJobs 项目中有几个关于这个问题的问题:
问题出在 DelayedJob 在 avery worker run 中使用的查询中:
UPDATE `delayed_jobs` SET `locked_at` = '2014-04-17 22:32:20', `locked_by` = 'host:b38f770a-f3f3-4b2a-8c66-7c8eebdb7fea pid:2' WHERE ((run_at <= '2014-04-17 22:32:20' AND (locked_at IS NULL OR locked_at < '2014-04-17 18:32:20') OR locked_by = 'host:b38f770a-f3f3-4b2a-8c66-7c8eebdb7fea pid:2') AND failed_at IS NULL) ORDER BY priority ASC, run_at ASC LIMIT 1
在我的情况下,少于 1000 个作业可能需要将近 1 秒的时间。随着待处理的作业越来越多,它会呈指数增长。
我找到的唯一解决方案是this blog 中公开的解决方案,简而言之:由于初始查询缺少适当的索引,因此解决方案是分批拆分表 em>:
-- stop workers
select max(id) from delayed_jobs; -- -> 10010
create table delayed_jobs_backup like delayed_jobs;
insert into delayed_jobs_backup select * from delayed_jobs where id < 10010;
delete from delayed_jobs where id < 10010;
-- start workers
-- while jobs in delayed_jobs_backup do
-- wait until the batch have been processed
insert into delayed_jobs select * from delayed_jobs_backup limit 1000;
delete from delayed_jobs_backup limit 1000;
-- end
【讨论】:
延迟作业未针对大量作业进行优化。长期的解决方案是改用 sidekiq (https://github.com/mperham/sidekiq) 之类的东西,但在短期内,您可以使用以下策略来清除您的延迟作业队列:
【讨论】:
对于 MySQL 5.6,在 failed_at 列上添加索引有很大帮助。
【讨论】: