实现循环队列的队列机制有哪些?

问题描述:

我有多个任务生产者将工作添加到队列中.我还有多个消费者从该队列中汲取营养.由于这些队列是先进先出的,因此它们按添加顺序出列.

I have multiple task producers that add work to a queue. I also have multiple consumers that feed off that queue. Since these queues are FIFO, they are dequeued in the same order they were added.

在我的场景中,任务从 HTTP 请求添加到队列中.每个任务都与一个帐户相关联,并且没有速率限制.因此,来自一个帐户的任务可能会淹没消息队列.

In my scenario, tasks are added to the queue from HTTP requests. Each task is associated with an account and there is no rate-limiting. Therefore it is possible to have tasks from one account flood the message queue.

为了解决这个问题,我一直在寻找一种队列实现,它允许我以循环方式处理来自多个帐户的排队任务,以确保公平.

In order to solve this, I've been looking for a queue implementation which allows me process enqueued tasks from multiple accounts in round-robin fashion for fairness.

我目前使用 Redis 和一些 Lua 脚本来模拟循环队列,但想知道是否有任何现有的队列拓扑可以实现这一点?

I've currently resorted to using Redis with some Lua scripts thrown in to emulate a round robin queue but was wondering if there are any existing queueing topologies that accomplish this?

我通常是这样做的:

  • 不要将任务直接放入工作队列,而是为每个帐户创建一个单独的任务队列.每个请求将一个任务放入其账户队列,当账户队列由空变为非空时,将账户队列放入全局工作队列

当工作人员准备好进行更多工作时,他们会从工作队列中考虑队列.当一个worker占用一个帐户队列时,它取出第一个任务,如果它不为空,worker立即将帐户队列放回工作队列的末尾.然后工作人员执行任务.

Workers take account queues from the work queue when they are ready for more work. When a worker takes an account queue, it takes out the first task and the worker immediately puts the account queue back at the end of the work queue if it's not empty. Then the worker performs the task.

使用此系统,每个帐户队列最多在工作队列中出现一次,并且所有与工作相关联的帐户在工作队列中均等地表示.

Using this system, each account queue is in the work queue at most once, and all accounts with associated work are equally represented in the work queue.

这很容易实现,但是您必须小心检测何时必须将帐户队列放入工作队列,因为可能有两个线程同时做出此决定,而您不需要'不希望帐户队列进入两次.

This is pretty easy to implement, but you do have to be careful about detecting when you have to put an account queue into the work queue, since there can be two threads making this decision at the same time, and you don't want the account queue to go in twice.

我把它简化成这样:

  • 在每个帐户队列中有一个原子布尔值,用于跟踪它是否在工作队列中.工作人员在帐户队列出列后立即将其设置为 false.如果有人发现帐户队列非空,他们可以尝试将此布尔值 CAS 设为 true,如果成功,则将帐户队列放入工作队列.

  • Have an atomic Boolean in each account queue that keeps track of whether or not it's in the work queue. The worker sets this to false immediately after dequeing the account queue. If anyone finds the account queue non-empty, they can try to CAS this boolean to true, and if successful put the account queue into the work queue.

帐户队列在空时进入工作队列的可能性很小.确保这是无害的——如果工作人员未能从帐户队列中获取任务,它应该忘记它并从工作队列中获取一个新的帐户队列.

There's a small chance that an account queue could get into the work queue when it's empty. Make sure this is harmless -- if a worker fails to take a task from an account queue, it should just forget about it and take a new account queue from the work queue.