批量数据库行到消息队列以进行长时间运行操作

时间:2010-01-08 18:40:45

标签: .net msmq message-queue

在预定时间(基于业务规则),我们需要来自数据库的10,000到200,000行之间的任何行,以便由长时间运行的操作进行处理。每一行都需要单独处理(它们不相互依赖),并且可以异步进行。必须记录成功完成操作(可能是数据库)。

我认为最好的方法是使用消息队列,因此它很耐用并且可以轻松扩展。首先,这是最好的解决方案吗?如果是这样,将数据库中的所有行放入队列的最有效方法是什么,保证所有行都进入队列?

注意:我们是一个使用C#3.5,WCF,MSMQ和SQL 2005的.Net团队。我调查过NServiceBus,如果推荐的话,他会愿意使用它。

我担心数据库是瓶颈(更新每一行以标记为已处理)。我也不知道如何“以交易方式发送”消息。

  1. 如何“以交易方式发送”消息?我的意思是:从db加载一行,发送消息,在db中更新行。如果更新失败,我不希望发送消息。
  2. 这是一种常见情况,还是应该以不同的方式进行?
  3. 我担心更新数据库中的各个行会导致瓶颈。我可以“交易发送”一批消息,然后批量更新数据库吗?

2 个答案:

答案 0 :(得分:2)

是。消息队列专为此事而设计。这就是他们的目的。消息队列解决方案可以扩展到天文大小。在队列本身成为限制因素之前,您将耗尽处理能力。

通常,您希望并发的单独进程执行这些操作。不要在线程解决方案上浪费单个大脑卡路里。您需要尽可能多的资源,操作系统级别的资源分配最适合此类事情。

您希望以最简单的方式执行以下操作。

  1. 创建队列。

  2. 创建几个从队列中读取的消费者进程。

  3. 开始制作流程。这将执行您的查询并编写队列,在此过程中尽可能少地执行。

  4. 每个消费者流程都将竞争队列中的条目。想想冰球队在空闲的消费者中的对峙。一旦消费者抓住它的行,就可以随心所欲地使用它。

    当查询为空时,您必须关闭所有内容。关闭消费者很难(但并非不可能)。在查询之后将一条特殊的“全部完成”消息放入队列中是很常见的。如果你有 n 消费者,你可以将这个全部完成的 n 副本放入队列中,这样消费者就可以全部关闭。

    请注意,这看起来很像Unix管道。这是一个很好的理由。


    编辑。

    1. 如何“以交易方式发送”消息?我的意思是:从db加载一行,发送消息,在db中更新行。如果更新失败,我不希望发送消息。

      不要这样做。一团糟。您的制作人发送消息。队列本身非常可靠。消息不会“迷路”或“以某种方式”无法处理。可以将队列配置为与文件系统一起使用,以便消息在消耗之前是持久的。

      消费者在完成任务后可以将事情标记为“已完成”。这会减慢很多事情。

      如果要保持“处理”状态,请使用数据仓库技术,不要将其与事务数据保持一致。

    2. 是的,这是一种常见的情况。每个人都试图在生产者方面做太多这样的事情。您很少需要您认为需要的所有“事务”处理。您必须详细说明最终用户的要求。你真的需要这个更新吗?或者只是因为你似乎应该在某处记录处理状态?

      记住队列非常可靠。不要重新发明数据库中的持久队列。

      在“交易消息”上阅读http://www.microsoft.com/windowsserver2003/techinfo/overview/msmqfaq.mspx。您有许多配置选项可以保证消息进入队列。

    3. 我担心更新数据库中的各个行会导致瓶颈。

      好好想想。所以不要这样做。数据库更新中的问题总是“为什么?”如果它是“完整性”,那就完全没有理由了。如果它是“用于恢复”或“防止重新处理”,您可能想要考虑更好的设计。

      在日志中执行插入操作要快得多,并且仍允许您执行where-not-exists查询,以便在必须恢复部分处理的历史记录的极不可能的情况下查找未处理的行。

    4. 最简单的队列是最好的。你很少需要大量的交易搞笑业务。只需将消息排队并在消费者方面完成工作。

答案 1 :(得分:2)

NServiceBus将使设置队列的过程变得更加容易。这个(msmq设计)是用于此操作的常见模式,但它不是您唯一的选择。

您还可以查看SQL Server Service Broker和许多其他类似技术来执行相同的操作。

MSMQ应该注意几点:

  1. 交易队列无法进行负载平衡,除非它们是Active Directory域队列。这里最重要的是队列必须在一台机器上,这意味着如果机器丢失(永久或暂时),它很容易丢失。这不是一个很大的问题,但需要注意
  2. MSMQ队列有两种“模式”事务性和非事务性。事务性队列是唯一保证消息传递的队列。
  3. MSMQ消息本身仅限于4MB(左右),您必须自己管理序列化(尽管使用XML序列化程序,默认的.NET序列化非常简单)。如果你想要大于4MB的消息,你需要在队列之外管理它们,或者自己管理多个排队的消息(BizTalk有一种方法可以做到这一点,所以它不是一个大问题)。 4MB应该足以满足您的需求。
  4. 一旦您“接受”队列中的消息,它就会被立即删除,因此根据您的设计,这可能是一个问题。消费者 可以“接受”消息,失败并让消息无法返回队列。
  5. 说了这么多,MSMQ非常可靠和稳定,如果您计划实施并将其用于流程的消息传递部分,而不是数据存储部分。

    最后,作为当前提案的替代方案(以及您可以比较的内容),您可以直接从数据库实施您描述的方案。作为餐巾纸素描:

    1. 进程在数据库中运行并填充一个表,其中包含要处理的“待处理”行,为每个行分配一个唯一的ID(guid等)
    2. 创建一个SP,将这些行的“n”返回给调用者,并在db中将这些行标记为“pending”。如果没有行,则返回0或-1,或任何
    3. 创建一个SP,它接收行ID的列表,以及作业的处置(完成信息)并更新挂起的表,标记它们或删除它们并记录完成数据
    4. 您的消费者会调用​​第一个SP并请求一组行来处理
    5. 您的消费者处理行
    6. 您的消费者致电第二个SP来记录完成的工作
    7. 然后,您可以定期运行报告以查看已完成的工作并且仍处于待处理状态,如果需要,可以将行从待处理更改为等待等。这将与您的其他解决方案大致相同,删除一层间接(可能是坏事,取决于)并提供稍微更线性的过程。这个过程本质上是Service Broker的工作方式(当然非常精炼)。

      这一切都取决于你最容易实现这一点。我已经做到了两种方式,两者都有其优点和缺点。