在预定时间(基于业务规则),我们需要来自数据库的10,000到200,000行之间的任何行,以便由长时间运行的操作进行处理。每一行都需要单独处理(它们不相互依赖),并且可以异步进行。必须记录成功完成操作(可能是数据库)。
我认为最好的方法是使用消息队列,因此它很耐用并且可以轻松扩展。首先,这是最好的解决方案吗?如果是这样,将数据库中的所有行放入队列的最有效方法是什么,保证所有行都进入队列?
注意:我们是一个使用C#3.5,WCF,MSMQ和SQL 2005的.Net团队。我调查过NServiceBus,如果推荐的话,他会愿意使用它。
我担心数据库是瓶颈(更新每一行以标记为已处理)。我也不知道如何“以交易方式发送”消息。
答案 0 :(得分:2)
是。消息队列专为此事而设计。这就是他们的目的。消息队列解决方案可以扩展到天文大小。在队列本身成为限制因素之前,您将耗尽处理能力。
通常,您希望并发的单独进程执行这些操作。不要在线程解决方案上浪费单个大脑卡路里。您需要尽可能多的资源,操作系统级别的资源分配最适合此类事情。
您希望以最简单的方式执行以下操作。
创建队列。
创建几个从队列中读取的消费者进程。
开始制作流程。这将执行您的查询并编写队列,在此过程中尽可能少地执行。
每个消费者流程都将竞争队列中的条目。想想冰球队在空闲的消费者中的对峙。一旦消费者抓住它的行,就可以随心所欲地使用它。
当查询为空时,您必须关闭所有内容。关闭消费者很难(但并非不可能)。在查询之后将一条特殊的“全部完成”消息放入队列中是很常见的。如果你有 n 消费者,你可以将这个全部完成的 n 副本放入队列中,这样消费者就可以全部关闭。
请注意,这看起来很像Unix管道。这是一个很好的理由。
编辑。
如何“以交易方式发送”消息?我的意思是:从db加载一行,发送消息,在db中更新行。如果更新失败,我不希望发送消息。
不要这样做。一团糟。您的制作人发送消息。队列本身非常可靠。消息不会“迷路”或“以某种方式”无法处理。可以将队列配置为与文件系统一起使用,以便消息在消耗之前是持久的。
消费者在完成任务后可以将事情标记为“已完成”。这会减慢很多事情。
如果要保持“处理”状态,请使用数据仓库技术,不要将其与事务数据保持一致。
是的,这是一种常见的情况。每个人都试图在生产者方面做太多这样的事情。您很少需要您认为需要的所有“事务”处理。您必须详细说明最终用户的要求。你真的需要这个更新吗?或者只是因为你似乎应该在某处记录处理状态?
记住队列非常可靠。不要重新发明数据库中的持久队列。
在“交易消息”上阅读http://www.microsoft.com/windowsserver2003/techinfo/overview/msmqfaq.mspx。您有许多配置选项可以保证消息进入队列。
我担心更新数据库中的各个行会导致瓶颈。
好好想想。所以不要这样做。数据库更新中的问题总是“为什么?”如果它是“完整性”,那就完全没有理由了。如果它是“用于恢复”或“防止重新处理”,您可能想要考虑更好的设计。
在日志中执行插入操作要快得多,并且仍允许您执行where-not-exists查询,以便在必须恢复部分处理的历史记录的极不可能的情况下查找未处理的行。
最简单的队列是最好的。你很少需要大量的交易搞笑业务。只需将消息排队并在消费者方面完成工作。
答案 1 :(得分:2)
NServiceBus将使设置队列的过程变得更加容易。这个(msmq设计)是用于此操作的常见模式,但它不是您唯一的选择。
您还可以查看SQL Server Service Broker和许多其他类似技术来执行相同的操作。
MSMQ应该注意几点:
说了这么多,MSMQ非常可靠和稳定,如果您计划实施并将其用于流程的消息传递部分,而不是数据存储部分。
最后,作为当前提案的替代方案(以及您可以比较的内容),您可以直接从数据库实施您描述的方案。作为餐巾纸素描:
然后,您可以定期运行报告以查看已完成的工作并且仍处于待处理状态,如果需要,可以将行从待处理更改为等待等。这将与您的其他解决方案大致相同,删除一层间接(可能是坏事,取决于)并提供稍微更线性的过程。这个过程本质上是Service Broker的工作方式(当然非常精炼)。
这一切都取决于你最容易实现这一点。我已经做到了两种方式,两者都有其优点和缺点。