我们有一个 Multi-Tenancy 应用程序,它运行 resque
进行后台处理。
我们偶尔会遇到的问题是,当单个租户在很短的时间内执行大量 后台工作时。这基本上会在一段时间内阻塞队列——当我们处理这个单个租户的积压工作时,其他所有租户的工作都被延迟了。
是的,我们可以添加更多的 worker 。但这并不是一个真正的“解决方案”,它更像是一个创可贴,它仍然会导致其他租户的延迟——只是随着我们处理速度的加快,延迟会更短。
是否有更多 Multi-Tenancy 友好的方式来使用 resque
?或者完全是一个对 Multi-Tenancy 更友好的后台队列?
我们正在考虑:
- 每个租户使用一个队列,每个租户使用一个工作人员(动态创建的队列?)
- 修改
resque
以便它以某种方式在每个租户的队列中循环
我们只是想知道是否有我们遗漏的东西/更好的方法...
最佳答案
您可以使用您的 Rails.cache
为每个参与者维护临时作业计数器,并根据事件作业的数量将作业分配到不同的队列。
您需要将作业子类化以支持不同的队列,并编写一个方法来解析作业的正确类。像这样的东西:
class Worker
cattr_acessor :tenant_id
class Worker::Low < Worker
@queue = :low
end
class Worker::High < Worker
@queue = :high
end
def self.queued
"#{name}::#{resolved_queue(tenant_id)}".constantize
end
def self.resolved_queue tenant_id
count = job_count(tenant_id)
if count > 1000
'Low'
else
'High'
end
end
def self.cache_key tenant_id
"job_count/#{tenant_id}"
end
def self.job_count tenant_id
Rails.cache.fetch(cache_key(tenant_id)){0}
end
def self.job_count_increment tenant_id
Rails.cache.fetch(cache_key(tenant_id)){0}
Rails.increment(cache_key(tenant_id)){0}
end
def self.job_count_decrement tenant_id
count = Rails.cache.fetch(cache_key(tenant_id)){0}
Rails.decrement(cache_key(tenant_id)){0} if count > 0
end
end
然后调用Worker.queued(tenant_id).perform
当你运行 worker 并确保 Worker.tenant_id
设置在 before_filters
在应用程序中。参见 Resque Priorities and Queue Lists有关队列和优先级的更多信息。
您应该在作业队列上调用递增并在作业中调用递减。
丑陋,但可行。
并且可以通过一些元编程变得更加枯燥——将这些方法提取到一个模块中,然后确保队列子类是在模块包含时生成的。
关于redis - Multi-Tenancy resque,避免一个租户阻塞队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33708349/