大量单线程任务队列

时间:2015-10-31 22:40:36

标签: java concurrency redis distributed task-queue

在我们公司,我们有一个服务器,分布在少数几个实例中。服务器处理用户请求。可以并行处理来自不同用户的请求。来自相同用户的请求应按顺序执行。但由于平衡,它们可以到达不同的实例。目前我们使用基于Redis的分布式锁,但这很容易出错,并且需要更多的并发工作而不是业务逻辑。

我想要的是这样的东西(更像是一个概念):

  • 每个用户的不同队列
  • 队列以用户ID
  • 命名
  • 请求ID
  • 标识的每个请求
  • 想象一下来自同一用户的两个请求同时到达两个不同的实例:

    1. 每个实例都将其请求ID放入此用户队列。
    2. 另外,他们都在本地存储他们的请求ID。
    3. 然后一些经纪人从" some_user_queue"的顶部获取请求ID。并将其移入" some_user_queue_processing"
    4. 两个实例都在监听" some_user_queue_processing"。他们偷看它,看看这是否是他们本地存储的请求ID。如果是,则进行处理。如果没有,那么忽略并等待。
    5. 完成工作后,服务器会从" some_user_queue_processing"中删除此ID。
    6. 然后再进行第3步。

所有这些都同时发生在很多(数千个)不同用户(以及他们的队列)上。

现在,我知道这听起来很像演员,但是:

  1. 我们需要尽可能少的变更解决方案,以便从锁定中快速转换。 Akka将迫使我们从头开始重写几乎所有内容。
  2. 我们需要生产就绪解决方案。 Quasar听起来不错,但尚未准备好生产(更准确地说,是他们的Galaxy集群)。
  3. 我的工作中非常保守,他们根本不想要另一种我们需要支持的依赖。但是我们已经使用Redis(用于分布式锁),所以我想也许它也可以帮助解决这个问题。
  4. 由于

1 个答案:

答案 0 :(得分:0)

与您的问题描述相符的最佳解决方案是Redis Cluster

基本上,集群通过以下方式解决了并发问题:

来自同一用户的两个(或多个)请求将始终转到同一个实例,假设您使用user-id作为键,请求作为值使用。该值实际上必须是list个请求。当您收到一个,您将其附加到该列表。换句话说,这就是您的请求队列(每个用户只有一个)。

通过集群实现的设计可以实现匹配。它基于遍布所有实例的一系列散列槽。

执行 set 命令时,集群执行散列操作,这会产生一个值(我们要写入的散列槽),它位于特定实例上。群集查找包含正确范围的实例,然后执行写入过程。

此外,当执行 get 时,群集执行相同的过程:它找到包含密钥的实例,然后获取值。

从锁定转换非常容易,因为您只需要准备好实例(启用了cluster-enabled指令" yes")然后从redis运行cluster-create命令-trib.rb脚本。

我去年夏天在生产环境中使用集群工作,表现非常好。