Rabbitmq 如何基于标准限制并发消息消耗

Rabbitmq 如何基于标准限制并发消息消耗,rabbitmq,spring-rabbit,Rabbitmq,Spring Rabbit,场景(我简化了事情): 许多最终用户可以从前端web应用程序(生产者)开始工作(繁重的工作,例如渲染大型PDF) 作业被发送到单个持久RabbitMQ队列 许多工作者应用程序(使用者)处理这些作业,并将结果写回数据存储 这种相当标准的模式运行良好 问题:如果一个用户在同一分钟内启动了10个作业,而一天中只有10个辅助应用程序启动,那么这个最终用户实际上是在为自己接管所有的计算时间 问题:如何确保每个最终用户在任何时候只处理一个作业?(奖金:某些最终用户(例如管理员)不得受到限制) 另外,我不

场景(我简化了事情):

  • 许多最终用户可以从前端web应用程序(生产者)开始工作(繁重的工作,例如渲染大型PDF)
  • 作业被发送到单个持久RabbitMQ队列
  • 许多工作者应用程序(使用者)处理这些作业,并将结果写回数据存储
这种相当标准的模式运行良好

问题:如果一个用户在同一分钟内启动了10个作业,而一天中只有10个辅助应用程序启动,那么这个最终用户实际上是在为自己接管所有的计算时间

问题:如何确保每个最终用户在任何时候只处理一个作业?(奖金:某些最终用户(例如管理员)不得受到限制)

另外,我不希望前端应用程序阻止最终用户启动并发作业。我只希望最终用户等待他们的并发作业一次完成一个


解决方案?:我是否应该为每个最终用户动态创建一个自动删除独占队列?如果是,我如何告诉工作应用程序开始使用此队列?如何确保一个(且只有一个)工作进程将从此队列中消费?

rabbitMQ本机不提供此类功能。 但是,您可以通过以下方式实现它。不过,您必须使用轮询,这并不是很有效(与订阅/发布相比)。您还必须利用Zookeeper来协调不同的工作人员

您将创建2个队列:1个高优先级队列(用于管理作业)和1个低优先级队列(用于正常用户作业)。这10名工作人员将从两个队列中检索消息。每个worker将执行一个无限循环(理想情况下,当队列为空时,具有睡眠间隔),在该循环中,它将尝试交换地从每个队列检索消息:

  • 对于高优先级队列,工作者只需检索消息、处理它并向队列确认
  • 对于低优先级队列,工作人员尝试在Zookeeper中保持锁定(通过写入特定文件znode),如果成功,则读取消息,对其进行处理并确认。如果zookeeper写入失败,则其他人持有锁,因此该工作人员跳过此步骤并重复循环

正如迪莫斯所说,您需要自己构建一些东西来实现这一点。这里有一个替代实现,它需要一个额外的队列和一些持久性存储

  • 与现有作业队列一样,创建一个“可处理作业队列”。只有满足业务规则的作业才会添加到此队列
  • 为作业队列创建使用者(名为“限制器”)。限制器还需要持久性存储(例如Redis或关系数据库)来记录当前正在处理的作业。限制器从作业队列读取数据并写入可处理作业队列
  • 工作应用程序完成作业处理后,会将“作业完成”事件添加到作业队列中

    ------------     ------------     ----------- 
    | Producer | -> () job queue ) -> | Limiter | 
    ------------     ------------     ----------- 
                         ^                |                    
                         |                V                    
                         |     ------------------------       
                         |    () processable job queue )  
           job finished  |     ------------------------       
                         |                |
                         |                V
                         |     ------------------------
                         \-----| Job Processors (x10) |
                               ------------------------
    
限制器的逻辑如下所示:

  • 收到作业消息后,请检查持久性存储器,以查看当前用户是否已在运行作业:
    • 如果没有,则将存储中的作业记录为正在运行,并将作业消息添加到可处理作业队列中
    • 如果现有作业正在运行,请将该作业作为挂起作业记录在存储器中
    • 如果作业是针对管理员用户的,请始终将其添加到可处理作业队列中
  • 收到“作业完成”消息后,将该作业从持久性存储器中的“正在运行的作业”列表中删除。然后检查存储器中该用户的挂起作业:
    • 如果找到作业,请将该作业的状态从“挂起”更改为“正在运行”,并将其添加到可处理作业队列中
    • 否则,什么也不做
  • 限制器进程一次只能运行一个实例。这可以通过只启动限制器进程的单个实例,或者通过在持久性存储中使用锁定机制来实现

它相当重,但是如果需要查看发生了什么,您可以随时检查持久存储。

一个工人一个队列。因此,您可以计算如下内容:userid%workercount,添加路由,如。因此,一次只能处理来自一个用户的一项任务。我发现这种方法存在三个问题:1)工作人员的数量必须相对稳定,才能使该算法正常工作;2)生产者需要实时了解消费者人数,3)如果一些用户开始的工作比其他用户多,则工作负荷可能无法在工人之间公平分配。谢谢,但我希望有人能帮助我了解如何设置RabbitMQ队列和交换以实现这一点(是否可能:)。如果我理解正确,您需要能够自动创建和终止工作进程并平均分配任务的功能。尝试添加调度程序节点取决于您有多少任务。调度程序将为用户添加队列,当工作程序结束所有用户任务时,它将向调度程序发送消息以删除队列。一个工作人员可以处理多个用户队列,但在您的情况下,只有一个工作人员可以处理一个用户(管理员除外)。使用redis或zookeeper控制正在处理的并发用户的数量。Robinho,是否要将您的评论扩展为答案?是否为每个可能上载文件的最终用户提供zookeeper锁?如果低优先级队列上的第一条消息是针对已经在处理某个内容的用户的,那么没有工作人员能够处理该队列上的任何消息?还是我误解了?我的问题已经提了几个月了。我现在已经切换到SQS而不是RabbitMQ。但我最初的问题仍然是,我的手指仍然有这个问题