Transactions Redis:具有多个密钥的事务

Transactions Redis:具有多个密钥的事务,transactions,redis,spring-data-redis,Transactions,Redis,Spring Data Redis,我正在使用SpringDataRedis。在Redis中,基本数据模型是 作业:包含作业数据的哈希 队列:包含用作队列的作业ID的列表 新作业将保存在作业哈希中,并将其推送到队列。我们有多个工作客户端汇集队列,通过弹出id并从散列中读取详细信息来使用新的作业id 现在,我正试图根据作业数据中的一些标志,开发出一个新特性,即某些工人只能使用某些作业。问题是,工作人员只有在读取作业的详细信息后才知道是否可以使用该作业,而不是在从队列中获取id时 我原本以为我可以把这一系列的操作放到一个事务中 偷看队

我正在使用SpringDataRedis。在Redis中,基本数据模型是

作业
:包含作业数据的哈希

队列
:包含用作队列的作业ID的列表

新作业将保存在
作业
哈希中,并将其推送到
队列
。我们有多个工作客户端汇集
队列
,通过弹出id并从散列中读取详细信息来使用新的作业id

现在,我正试图根据作业数据中的一些标志,开发出一个新特性,即某些工人只能使用某些作业。问题是,工作人员只有在读取作业的详细信息后才知道是否可以使用该作业,而不是在从队列中获取id时

我原本以为我可以把这一系列的操作放到一个事务中

  • 偷看队列
  • 从散列中读取作业详细信息并检查是否可用
  • 如果是,则从队列中获取其id,否则不执行任何操作

  • 然而,这种事务同时涉及队列和散列数据。在阅读了Redis的事务支持之后,我不确定这是否可以实现。请帮助建议我应该采取什么方法。

    Redis事务与关系数据库事务略有不同,因为它们更好地描述为条件批处理。事务是一堆在发出命令时排队的命令。一旦
    EXEC
    执行事务,命令就会执行,并且命令响应会在
    EXEC
    命令的响应中返回

    在我看来,现在还没有必要进行交易。定期窥视队列是幂等的,因此如果它发生多次,就不会有任何中断。阅读作业详细信息也一样。由于另一个节点可能更快,并且已经处理了作业,因此在尝试读取时,您应该期望作业详细信息消失。这是一个典型的种族状况,尽早识别这些是有益的


    现在是关键部分:从队列中获取作业通常是保证原子性的
    BLPOP
    /
    BRPOP
    。您没有说明一旦工作完成,工作细节应该发生什么。我假设删除散列。因此,
    BLPOP
    队列和
    DEL
    作业散列将是将它们放入事务的候选对象,但这取决于您的用例和条件。特别是至少一次和最多一次的行为。

    < P>如果你想避开轮询/窥视/竞争条件,你可以考虑以下内容:

  • 将现有队列保持为通用输入队列,并从该队列中设置一个轻量级分类类型的工作人员(一个可能足够了,但您可以有更多冗余)pop项,使用阻塞pop避免轮询,并根据作业分配逻辑将新项推送到每个工作人员类型的单独队列中

  • 创建多个worker,其中每个worker从其自己的worker类型队列中发出阻塞pop

  • 将队列分为多个队列的一个优点是,您可以在监视中获得更多的可见性,因为您可以检查每个队列的长度,并查看哪些类型的工作人员运行缓慢


    它可能不适合生产使用,但您可能对内存中的分布式作业队列感兴趣,该队列由与Redis相同的作者创建(并基于Redis代码)。

    好主意!我的同事提出了一种更简单的方法,让工人在无法处理作业时将作业推回到队列中,但这看起来是一种更高级的解决方案,我们肯定会尝试一下。谢谢。您可能还想考虑为重复处理失败的消息创建一个“死信队列”,以避免一个让整个系统停顿的冒险工作。如果失败的原因是暂时的,则可以重播死信队列。还要注意的是,我扩展了我的答案,提到了Disque(值得一看,因为它可能在将来有用)