数据库队列的并发问题,需要便携式解决方案

时间:2011-04-05 02:27:11

标签: mysql sql-server concurrency locking thread-safety

我在SQL数据库(当前是MS SQL Server)中实现了一个传入消息队列,可以通过Web服务访问。此Web服务运行我们无法控制的旧协议,并且必须返回“队列中没有消息”响应,或两者都返回:

  • 队列中最早的消息的详细信息
  • 队列中其他消息的数量

用于此目的的算法目前非常粗糙:

  1. 选择队列中的所有邮件
  2. 剩余消息数=行数 - 1
  3. 更新最旧的消息以设置收集的标志
  4. 我们正在转向现在可以同时访问它的情况,并且显然遇到并发问题,其中相同的消息被拾取两次。

    我们遇到的问题是,我们需要可移植解决方案,并且最低部署要求。理想情况下,这意味着没有存储过程,也没有特定于引擎的锁。

    有没有人有任何好主意?

    谢谢!

2 个答案:

答案 0 :(得分:2)

由于您已经在使用SQL服务器,因此应该考虑使用SQL Server Service Broker

然而,这会将您绑定到SQL服务器......

你可能会考虑的一件事是你做一个选择...得到一个ROW ID ...更新ROW以将其标记为使用您生成的新rowID(guid或类似)收集...再选择它...如果行id是你设置的那个,那么你就是那个得到它...如果没有人在你面前进入你必须得到另一个。

基本上你自己实现了脏读保护......因为你不想使用事务或存储过程......

答案 1 :(得分:1)

最终,考虑到您描述的约束,出列必须一次完成一条消息 - 然而,除了数据库事务(所有Web服务处理)之外,还有更多涉及将消息传递给订阅者的内容代码,网络和HTTP延迟)。

当前的系统在事务控制方面没有明显的实现 - 所以我认为这对于并发解决方案来说也不是问题。

如果是我,我会设置一个存储过程(为什么你认为它们不可移植?)与一个带有可序列化锁的事务中的操作 - 我还要用一个缓存队列消息的数量TTL基于缓存值的操作数/年龄,以减少基础表上昂贵的聚合操作的数量。这可以通过从controllnig语言一次发出DML操作来完成 - 但是净效果是操作将花费更长的时间。

另一种方法(使得实现锁定更容易)将是对数据进行分片 - 不确定MSSQL是否支持命名锁 - 当然它不是一个非常便携的解决方案 - 因此将数据拆分为单独的表并使用表锁。这使得实现事务控制变得更加简单 - 但是负载消隐/顺序处理存在问题(但同样,并发方法适用于后者并不是一个大问题。)