我遇到了一个问题,即在极少数情况下,来自事务性 MSMQ 队列的消息被接收两次。
这是我的设置(3 个 Windows 2008 R2 x64 服务器):
- 托管专用队列的 MSMQ 服务器。它们被配置为事务性的。
- 2 托管工作流 (WF4) 的服务器通过 WCF 从 MSMQ 服务器上的远程专用队列接收消息。
- 每个队列有 2 个接收器,每个服务器 1 个接收器。我希望当一台服务器从队列中拉出一条消息时,该消息无法再次处理。
- 以事务方式接收消息(TransactionScopeRequired = true)
- 接收者的 netMsmqBinding 有
exactlyOnce="true"
- 每条收到的消息都会触发工作流实例的创建。我正在使用自定义 WorkflowHostingEndpoint,因此我可以根据消息的内容设置工作流 ID。
有时重复消息仅出现在其中一个服务器上,有时重复消息出现在两台服务器中的每一个上。这只发生在有大量消息要处理,并且总是在很短的时间范围内(通常 < 200 毫秒)内收到重复的消息时。
我可以检测到一条消息被接收了两次,因为每条消息都包含一个唯一的 GUID,它用作插入数据库的主键。当收到两次消息时,我在日志文件中看到主键违规错误。
我打开了 WCF 服务模型和消息跟踪,看到使用两个不同的分布式事务接收了两次消息。在这种情况下,这发生在同一台服务器上。
2012-08-16T08:31:18.4874394Z: Thread 210: Message Log Trace (message contains unique GUID 43df02cc-79c7-48ca-995f-175c22fb9e59)
2012-08-16T08:31:18.4874394Z: Thread 210: The transaction '69acc04f-4853-4680-bc13-3855f5b844d4:3782' was received for operation 'CreateWorkflow' from a transacted transport, such as MSMQ.
2012-08-16T08:31:18.6434444Z: Thread 207: Message Log Trace (message contains unique GUID 43df02cc-79c7-48ca-995f-175c22fb9e59)
2012-08-16T08:31:18.6434444Z: Thread 207: The transaction '69acc04f-4853-4680-bc13-3855f5b844d4:3789' was received for operation 'CreateWorkflow' from a transacted transport, such as MSMQ.
什么会导致这种情况发生,我该如何防止这种情况发生?
更新:这是我用于发送消息的相关代码。我如何发送消息不应该影响接收消息的方式,对吧?是不是在发送方打开 TransactionScope 会在发送方和接收方之间创建分布式事务?这真的不是本意。
private static readonly ChannelFactory<IWorkflowCreation> _channelFactory =
new ChannelFactory<IWorkflowCreation>(new NetMsmqBinding(NetMsmqSecurityMode.None));
private void StartWorkflow(EndpointAddress address, WorkflowData data)
{
using (var scope = new TransactionScope())
{
var client = _channelFactory.CreateChannel(address);
using ((IClientChannel)client)
{
client.CreateWorkflow(data);
}
scope.Complete();
}
}