集中式数据库:多个消费者

本文关键字:消费者 数据库 集中式 | 更新日期: 2023-09-27 18:01:19

我有一个表,其中包含启动数据和在本地网络中不同机器上运行的多个消费者应用程序。

请建议我如何组织他们从这个数据库中只取一次每条记录,这样就不会有2个或更多的应用程序从表中获取相同记录的任何情况。

我看到两种可能的方法来解决它,但不确定:

  1. 另一个应用程序将接收来自消费者应用程序的请求,并为他们提供唯一的未处理记录,
  2. 在数据库中实现一些存储过程

请告知. .

集中式数据库:多个消费者

要检索行,创建一个存储过程:

  • 启动事务
  • 选择并锁定可用的行
  • 更新该行的一列,以标记它不可用于其他
  • 提交事务
  • 将行传递给客户端

要更新行,创建一个存储过程:

  • 开始一个事务
  • 更新行(可选择检查rowversion)
  • 更新行
  • 的可用性
  • 提交事务
额外的

:

  • 你可能想要添加一个日期/时间到行,这样你就会知道什么时候一行被锁定
  • 如果一行被锁定了很长时间(比您预期的时间长),您可以释放锁并让其他人选择该行。然而,为了防止前一个所有者更新(他不知道他丢失了锁),你应该在表中有一个rowversion列。
  • 你可以将(un)可用状态保存在一个单独的表中,这样可以更容易地找到可用的行。

多种选择:

  • 使用交易,并在获取交易时将每条记录标记为正在进行中;永远不要记录已经标记为"进行中"的记录(注意:您可能需要"取消标记"花费太长时间的项目,例如机器死机)
  • 使用随机排序(可能是NEWID)来选择不太可能
  • 冲突的行。
然而,我个人认为还有其他的存储隐喻在这里工作得很好,例如"redis"有一些合适的操作:
  • RPOPLPUSH(在列表之间移动1条记录,并返回)
  • SPOP(随机删除并返回1条记录)
  • RPOP/LPOP(从列表末尾删除并返回1条记录)

所有这些都是原子的,避免了在SQL中造成痛苦的所有位。

用ProcessedBy添加一个字段到表中,如果没有机器开始处理它,可以将值设置为null,如果开始处理,则将值设置为机器名。在获取记录时,您可以验证此processedBy字段,如果它为空,则可以将其分配给任何机器。

您要求的是默认数据库行为。您可以使用"SELECT ......"FOR UPDATE",数据库引擎将锁定该行,使其对其他用户不可用。然而,这只是一个好的实践,如果你的程序想要保存数据很短的时间(少于1秒),你的应用程序保存数据的时间更长,会遇到很多死锁和争用问题。

您可以在应用程序代码中通过拥有一对列,如"RESERVED_BY_USER"answers"RESERVED_UNTIL"来实现这一点,应用程序可以自己管理它们。

然而,从你所描述的,我认为你真正想要的是这里描述的队列