使用RabbitMQ作为分布式代理 - 如何为每个队列序列化作业

时间:2014-06-08 09:44:46

标签: rabbitmq message-queue worker job-queue

我系统中的每个作业都属于特定的用户ID,可以从多个来源放入rabbitmq。我的要求:

  • 在任何给定时间,每个用户不应运行多于1个作业。
  • 其他用户的工作不应因为特定用户的工作堆积而遇到任何延迟。
  • 每项工作至少应执行一次。每个作业将具有最大重试次数,并且如果失败则重新插入队列(或可能延迟)并延迟。
  • 维护作业顺序(每个用户)是可取的,但不是强制性的。
  • 乔布斯应该坚持下去,因为我需要他们执行至少一次。没有工作的到期时间。
  • 任何工作人员都应该能够为任何用户运行作业。

根据这些要求,我认为为每个用户维护一个队列是有道理的。我还需要所有工作人员观察所有用户队列并为用户执行作业,其作业当前没有在任何地方运行(即,每个用户不超过1个作业)

此解决方案是否可以在群集设置中使用RabbitMQ?由于队列数量很大,我不确定每个工作人员观察每个用户队列是否会造成很大的开销。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:1)

正如@dectarin所提到的,让多个工作人员监听多个作业队列将使得很难确保每个用户只执行一个作业。

如果工作经历了几个步骤,我认为它会更好。

  1. 用户提交作业
  2. 作业按用户排队,直到没有其他作业正在运行
  3. 协调员将工作放在工作人员消耗的活动作业队列上
  4. 工作人员接受工作并执行它
  5. 工作人员将结果发布在结果队列中
  6. 结果将发送给用户
  7. 我不知道如何将作业提交到系统,因此很难判断实际的每用户MessageQueues是否是排队等待的最佳方式。例如,如果作业已经位于邮箱中,那么这可能也会起作用。或者将排队的作业存储在数据库中,作为奖励,允许您为用户编写一个前端,以检查和管理他们的排队作业。

    根据您的选择,您可以找到一种优雅的方式来协调每个用户约束的单个作业。

    例如,如果作业位于数据库中,则数据库会保持同步,并且多个协调员工作者可以通过以下循环:

    while( true ) {
        if incoming job present for any user {
            pick up first job from queue
            put job in database, marking it active if no other active job is present
            if job was marked active {
                put job on active job queue
            }
        }
        if result is present for any user {
            pick up first result from result queue
            send results to user
            mark job as done in database
            if this user has job waiting in database, mark it as active
            if job was marked active {
                put job on active job queue
            }
        }
    }
    

    或者如果等待的作业位于每个用户的消息队列中,事务将更容易,并且单个协调器通过循环不需要担心多线程。

    跨数据库和队列完全事务处理可能很困难,但不一定非必要。引入待处理状态时,您应该谨慎行事,确保在步骤失败时不会丢失任何作业。