简体   繁体   English

SQL Server,使用表作为队列

[英]SQL Server, using a table as a queue

I'm using an SQL Server 2008 R2 as a queuing mechanism. 我使用SQL Server 2008 R2作为排队机制。 I add items to the table, and an external service reads and processes these items. 我将项添加到表中,外部服务读取并处理这些项。 This works great, but is missing one thing - I need mechanism whereby I can attempt to select a single row from the table and, if there isn't one, block until there is (preferably for a specific period of time). 这很好用,但缺少一件事 - 我需要机制,我可以尝试从表中选择一行,如果没有,则阻塞直到有(优选在特定的时间段内)。

Can anyone advise on how I might achieve this? 任何人都可以建议我如何实现这一目标?

The only way to achieve a non-pooling blocking dequeue is WAITFOR (RECEIVE) . 实现非池阻塞队列的唯一方法是WAITFOR (RECEIVE) Which implies Service Broker queues, with all the added overhead. 这意味着Service Broker队列具有所有增加的开销。

If you're using ordinary tables as queues you will not be able to achieve non-polling blocking. 如果您使用普通表作为队列 ,则无法实现非轮询阻止。 You must poll the queue by asking for a dequeue operation, and if it returns nothing, sleep and try again later. 您必须通过请求出列操作来轮询队列,如果它没有返回任何内容,请休眠并稍后再试。

I'm afraid I'm going to disagree with Andomar here: while his answer works as a generic question 'are there any rows in the table?' 我担心我会在这里不同意Andomar:虽然他的答案是一个普遍的问题,但桌子上有没有排? when it comes to queueing, due to the busy nature of overlapping enqueue/dequeue, checking for rows like this is a (almost) guaranteed deadlock under load. 当涉及到排队时,由于重叠入队/出队的繁忙性质,检查这样的行是一个(几乎)保证在负载下的死锁。 When it comes to using tables as queue, one must always stick to the basic enqueue/dequeue operations and don't try fancy stuff. 当使用表作为队列时,必须始终坚持基本的入队/出队操作,不要尝试花哨的东西。

"since SQL Server 2005 introduced the OUTPUT clause, using tables as queues is no longer a hard problem". “自SQL Server 2005引入OUTPUT子句以来,使用表作为队列不再是一个难题”。 A great post on how to do this. 关于如何做到这一点的好文章。

http://rusanu.com/2010/03/26/using-tables-as-queues/ http://rusanu.com/2010/03/26/using-tables-as-queues/

I need mechanism whereby I can attempt to select a single row from the table and, if there isn't one, block until there is (preferably for a specific period of time). 我需要一种机制,我可以尝试从表中选择一行,如果没有,则阻塞直到有(优选在特定的时间段内)。

You can loop and check for new rows every second: 您可以每秒循环并检查新行:

while not exists (select * from QueueTable)
    begin
    wait for delay '00:01'
    end

Disclaimer: this is not code I would use for a production system, but it does what you ask. 免责声明:这不是我将用于生产系统的代码,但它可以满足您的要求。

The previous commenter that suggested using Service Broker likely had the best answer. 之前提出使用Service Broker的评论者可能得到了最好的答案。 Service Broker allows you to essentially block while waiting for more input. Service Broker允许您在等待更多输入时实质上阻止。

If Service Broker is overkill, you should consider a different approach to your problem. 如果Service Broker过度,您应该考虑采用不同的方法解决问题。 Can you provide more details of what you're trying to do? 你能提供你想要做的更多细节吗?

Let me share my experiences with you in this area, you may find it helpful. 让我分享一下我在这方面的经历,你会发现它很有帮助。

My team first used MSMQ transactional queues that would feed our asynchronous services (be they IIS hosted or WAS). 我的团队首先使用MSMQ事务队列来提供我们的异步服务(无论是IIS托管还是WAS)。 The biggest problem we encountered was MS DTC issues under heavy load, like 100+ messages/second load; 我们遇到的最大问题是重负载下的MS DTC问题,例如100多条消息/秒负载; all it took was one slow database operation somewhere to start causing timeout exceptions and MS DTC would bring the house down so to speak (transactions would actually become lost if things got bad enough), and although we're not 100% certain of the root cause to this day, we do suspect MS DTC in a clustered environment has some serious issues. 所有这一切都是一个缓慢的数据库操作,开始导致超时异常和MS DTC会让房子倒闭(如果事情变得很糟糕,交易实际上会丢失),虽然我们不是100%确定根直到今天,我们怀疑群集环境中的MS DTC存在一些严重问题。

Because of this, we started looking into different solutions. 因此,我们开始研究不同的解决方案。 Service Bus for Windows Server (the on-premise version of Azure Service Bus) looked promising, but it was non-transactional so didn't suit our requirements. Windows Server的Service Bus(Azure Service Bus的内部部署版本)看起来很有前途,但它是非事务性的,因此不符合我们的要求。

We finally decided on the roll-your-own approach, an approach suggested to us by the guys who built the Azure Service Bus, because of our transactional requirements. 由于我们的事务要求,我们最终决定采用自己动手的方法,这是由构建Azure Service Bus的人员向我们建议的方法。 Essentially, we followed the Azure Worker Role model for a worker role that would be fed via some queue; 从本质上讲,我们遵循Azure Worker Role模型来获取将通过某个队列提供的辅助角色; a polling-blocking model. 一个轮询阻止模型。

Honestly, this has been far better for us than anything else we've used. 老实说,这对我们来说比我们使用过的任何东西都要好得多。 The pseudocode for such a service is: 这种服务的伪代码是:

hasMsg = true

while(true)

    if(!hasMsg)
         sleep

    msg = GetNextMessage

    if(msg == null)
        hasMsg = false
    else
        hasMsg = true

    Process(msg);

We've found that CPU usage is significantly lower this way (lower than traditional WCF services). 我们发现这种方式的CPU使用率明显较低(低于传统的WCF服务)。

The tricky part of course is handling transactions. 当然,棘手的部分是处理交易。 If you'd like to have multiple instances of your service read from the queue, you'll need to employ read-past/updlock in your sql, and also have your .net service enlist in the transactions in a way that will roll-back should the service fail. 如果您希望从队列中读取多个服务实例,则需要在sql中使用read-past / updlock,并且还要让.net服务以一种滚动的方式登记到事务中。如果服务失败了。 in this case, you'll want to go with retry/poison queues as tables in addition to your regular queues. 在这种情况下,除了常规队列之外,您还需要将重试/毒药队列作为表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM