2008-11-17 113 views
14

我有一个数据库表,里面有〜50K行,每行代表一个需要完成的工作。我有一个程序从数据库中提取作业,完成作业并将结果放回到数据库中。 (这个系统现在正在运行)使用数据库表作为消息/作业队列的最佳方法

现在我想允许多个处理任务执行任务,但要确保没有任务执行两次(因为性能问题不会导致其他问题)。因为访问是由sproce的方式,我现在虽然是替代说sproce的东西,看起来像这样

update tbl set owner=connection_id() where avalable and owner is null limit 1; 
select stuff from tbl where owner = connection_id(); 

BTW;工人的任务可能会降低找工作和提交结果之间的联系。此外,我不认为数据库甚至会接近瓶颈,除非我弄糟那部分(每分钟~5个工作)

这是否有任何问题?有一个更好的方法吗?

注意:"Database as an IPC anti-pattern"在这里只是略有倾向,因为1)我没有做IPC(没有进程生成行,它们现在都已经存在),2)描述了反模式的主要抱怨是因为进程等待消息导致数据库上不需要的负载(在我的情况下,如果没有消息,所有事情都可以关闭,因为一切都完成了)

+0

Right - bad =同步IPC,在dbms上作为一个读作为SELECT进行阻塞。你大概是在做这个引入异步性的策略。 – dkretz 2008-11-18 00:21:59

+0

顺便说一句,如果你想把阅读器放在定时器上,让它们不频繁检查是很有用的,但是如果它们找到工作,它们可以在再次睡觉之前排空队列。 – dkretz 2008-11-18 00:23:31

+0

请注意我的编辑:如果他们找不到工作,他们将永远找不到工作。但是,如果这不是真的...... – BCS 2008-11-18 00:26:23

回答

12

这就是我已经在过去成功应用于:

MsgQueue表模式

MsgId identity -- NOT NULL 
MsgTypeCode varchar(20) -- NOT NULL 
SourceCode varchar(20) -- process inserting the message -- NULLable 
State char(1) -- 'N'ew if queued, 'A'(ctive) if processing, 'C'ompleted, default 'N' -- NOT NULL 
CreateTime datetime -- default GETDATE() -- NOT NULL 
Msg varchar(255) -- NULLable 

你的消息类型你所期望 - 符合流程插入和流程读取之间契约的消息,使用XML或您的其他表示形式(例如,在某些情况下JSON会很方便)构建。

然后可以插入0到n个进程,并且0到n个进程可以读取和处理消息。每个读取进程通常处理单个消息类型。可以运行多个进程类型的实例来进行负载平衡。

阅读器读取一条消息,并在其工作时将状态更改为“A”。完成后,它将状态更改为“C”完成。它可以删除或不删除,具体取决于您是否要保留审计线索。 State ='N'的消息以MsgType/Timestamp顺序拉取,因此在MsgType + State + CreateTime上有一个索引。

变化:
状态为“E”rror。
读取器进程代码的列。
状态转换的时间戳。

这提供了一个很好的,可扩展的,可见的,简单的机制来完成许多事情,比如你所描述的。如果你对数据库有一个基本的了解,那么它是非常简单和可扩展的。从评论


代码:

CREATE PROCEDURE GetMessage @MsgType VARCHAR(8)) 
AS 
DECLARE @MsgId INT 

BEGIN TRAN 

SELECT TOP 1 @MsgId = MsgId 
FROM MsgQueue 
WHERE MessageType = @pMessageType AND State = 'N' 
ORDER BY CreateTime 


IF @MsgId IS NOT NULL 
BEGIN 

UPDATE MsgQueue 
SET State = 'A' 
WHERE MsgId = @MsgId 

SELECT MsgId, Msg 
FROM MsgQueue 
WHERE MsgId = @MsgId 
END 
ELSE 
BEGIN 
SELECT MsgId = NULL, Msg = NULL 
END 

COMMIT TRAN 
-1

您正试图实现de“Database as IPC”反模式。查看它以了解为什么你应该考虑重新设计你的软件。

+1

你怎么知道这是一个反模式在这种情况下,或者软件设计不合适?您无论如何都没有任何基于此评论的背景。 – 2008-11-17 23:08:40

0

而不是拥有owner = null时,你应该将它设置为一个假的无人记录,而不是。搜索空值不会限制索引,您最终可能会进行表扫描。 (这是Oracle,SQL服务器可能会有所不同)

1

正如一个可能的技术变化,你可能会考虑使用MSMQ或类似的东西。

您的每个作业/线程都可以查询消息队列以查看是否有新作业可用。由于阅读消息的行为会将其从堆栈中移除,因此可以确保只有一个作业/线程会收到消息。

当然,这是假定您正在使用Microsoft平台。

相关问题