自托管 NServiceBus ASP.NET 端点而非其他进程的 MSDTC 失败
MSDTC fails for self-hosted NServiceBus ASP.NET endpoints but not other processes
我有一个 Windows 2008 R2 服务器,它托管许多后端 NServiceBus 端点。所有依赖于 NServiceBus.Host.exe 主机(安装为 Windows 服务)的服务都能够与 MSDTC 完美交互,全天平均有少量并发分布式事务。然而,有 2 个小型 Web.API 应用程序自托管 NServiceBus 端点(作为发布者),它们在尝试处理订阅请求时不断收到以下错误:
NServiceBus.Transports.Msmq.MsmqDequeueStrategy Error in receiving
messages. System.Transactions.TransactionAbortedException: The
transaction has aborted. --->
System.Transactions.TransactionManagerCommunicationException:
Communication with the underlying transaction manager has failed. --->
System.Runtime.InteropServices.COMException: The Transaction Manager
is not available. (Exception from HRESULT: 0x8004D01B) at
System.Transactions.Oletx.IDtcProxyShimFactory.ConnectToProxy(String
nodeName, Guid resourceManagerIdentifier, IntPtr managedIdentifier,
Boolean& nodeNameMatches, UInt32& whereaboutsSize, CoTaskMemHandle&
whereaboutsBuffer, IResourceManagerShim& resourceManagerShim) at
System.Transactions.Oletx.DtcTransactionManager.Initialize() ---
End of inner exception stack trace --- at
System.Transactions.Oletx.OletxTransactionManager.ProxyException(COMException
comException) at
System.Transactions.Oletx.DtcTransactionManager.Initialize() at
System.Transactions.Oletx.DtcTransactionManager.get_ProxyShimFactory()
at
System.Transactions.Oletx.OletxTransactionManager.CreateTransaction(TransactionOptions
properties) at
System.Transactions.TransactionStatePromoted.EnterState(InternalTransaction
tx) --- End of inner exception stack trace --- at
System.Transactions.TransactionStateAborted.CheckForFinishedTransaction(InternalTransaction
tx) at System.Transactions.Transaction.Promote() at
System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction
transaction) at
System.Transactions.TransactionInterop.GetDtcTransaction(Transaction
transaction) at
System.Messaging.MessageQueue.StaleSafeReceiveMessage(UInt32 timeout,
Int32 action, MQPROPS properties, NativeOverlapped* overlapped,
ReceiveCallback receiveCallback, CursorHandle cursorHandle, IntPtr
transaction) at
System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32
action, CursorHandle cursor, MessagePropertyFilter filter,
MessageQueueTransaction internalTransaction,
MessageQueueTransactionType transactionType) at
System.Messaging.MessageQueue.Receive(TimeSpan timeout,
MessageQueueTransactionType transactionType) at
NServiceBus.Transports.Msmq.MsmqDequeueStrategy.ReceiveMessage(Func`1
receive) in
c:\BuildAgent\workf8c64a6e8a2d7c\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line
313
一些其他注意事项:
- 错误的 ApplicationPools 身份和 Windows
服务的登录用户是相同的。
- 这在之前确实很管用
最近重新启动,因为 Web.API 服务能够成功
处理订阅请求,并且能够仅发布消息
很好(尽管发布不会自动使用 MSDTC,而且我们
不显式使用 TransactionScope)。自从本地重启后,我们
如果订阅请求消息存在,只需得到上述错误
在任一 Web.API 发布者的输入队列中。
- 我已经使用了 procmon.exe 和 MSDTC 跟踪,但没有发现任何有用的东西。典型的事件查看器日志也不提供任何信息。
- 所有端点都是 运行 .NET 4.5 和 NServiceBus 4.6
- 我们不能
在任何其他环境中重新创建它。
以下对话的补充说明
- 抛出异常的线程是纯NServiceBus订阅管理,涉及"my"个none个代码。当应用程序池按需启动 w3wp.exe 工作进程时,NSB 会生成一个应用程序不知道的工作线程来处理订阅请求。它 应该 只能跨发布者的输入队列和订阅存储工作,我也在使用 MSMQ,在另一个队列中(即不涉及其他服务器)据我所知)。
- 网站的 "code" 在重新启动后没有变化,应用程序池在重新启动之前停止并重新启动了几次,没有问题。
不是真正的答案,但评论太长了。
您的操作的哪一部分需要 DTC?分布式事务会在需要时自动登记,通常是在您与两个不同的支持 DTC 的基础设施(例如 MSMQ 和数据库)对话时。
您说您通过 DTC 跟踪进行了测试——您是说 DTC Ping 吗?您是否通过在两台机器(或所有机器,如果交易中涉及多于两台机器)上使用 运行 进行测试? DTC 工具非常深奥,其输出可能令人困惑。
另外,如果它在重启前确实有效,是否可以重启重置防火墙设置?防火墙是 DTC 问题的常见原因。
此外,我假设您检查并重新检查了本地机器上的 DTC 设置?您是否确保将 MSMQ 队列设置为事务性队列?
来自您的评论:
Note that this particular failure occurs when attempting to dequeue a
message from a local private MSMQ queue [...]
堆栈跟踪显示它正在做的就是这些,但我怀疑它在尝试出队时也在尝试征集多个服务器之间的事务。见下文。
Why MSDTC? It's the original way to support exactly-once messaging in
NServiceBus (see here).
是的,但我要问的是为什么特定操作 需要 分布式事务。如果处理程序所做的只是从队列中读取和(例如)将输出写入控制台,则 MSDTC 将永远不会被征用,即使处理程序被包装在事务范围内也是如此。它将简单地使用本地事务从队列中读取。升级到分布式事务是自动的,只有在需要支持多个基础架构时才会发生。
因此,如果您最近在将数据写入新数据库服务器的处理程序中部署了代码,您可能会遇到故障,因为您现在正在征用包含新服务器的事务,这可能是发生故障的地方.
所以确定分布式事务涉及的所有服务器是第一步。下一步是检查所有相关服务器上的 DTC 设置。如果 DTC 设置不是问题,我建议使用 DTCPing 测试服务器之间的通信。 NServiceBus documentation 有一些关于使用 DTCPing 的很好的说明。
"fixed" 这对我们在生产环境中的作用是将应用程序池身份用户添加到服务器上的本地管理员组。不幸的是,我们没有时间确定哪些设置需要安全设置,因为这在其他类似服务器中不是必需的配置。此外,从安全角度来看,这不是最理想的解决方案,但在我们的特定情况下,我们愿意接受它。
我有一个 Windows 2008 R2 服务器,它托管许多后端 NServiceBus 端点。所有依赖于 NServiceBus.Host.exe 主机(安装为 Windows 服务)的服务都能够与 MSDTC 完美交互,全天平均有少量并发分布式事务。然而,有 2 个小型 Web.API 应用程序自托管 NServiceBus 端点(作为发布者),它们在尝试处理订阅请求时不断收到以下错误:
NServiceBus.Transports.Msmq.MsmqDequeueStrategy Error in receiving messages. System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.Transactions.TransactionManagerCommunicationException: Communication with the underlying transaction manager has failed. ---> System.Runtime.InteropServices.COMException: The Transaction Manager is not available. (Exception from HRESULT: 0x8004D01B) at System.Transactions.Oletx.IDtcProxyShimFactory.ConnectToProxy(String nodeName, Guid resourceManagerIdentifier, IntPtr managedIdentifier, Boolean& nodeNameMatches, UInt32& whereaboutsSize, CoTaskMemHandle& whereaboutsBuffer, IResourceManagerShim& resourceManagerShim) at System.Transactions.Oletx.DtcTransactionManager.Initialize() --- End of inner exception stack trace --- at System.Transactions.Oletx.OletxTransactionManager.ProxyException(COMException comException) at System.Transactions.Oletx.DtcTransactionManager.Initialize() at System.Transactions.Oletx.DtcTransactionManager.get_ProxyShimFactory() at System.Transactions.Oletx.OletxTransactionManager.CreateTransaction(TransactionOptions properties) at System.Transactions.TransactionStatePromoted.EnterState(InternalTransaction tx) --- End of inner exception stack trace --- at System.Transactions.TransactionStateAborted.CheckForFinishedTransaction(InternalTransaction tx) at System.Transactions.Transaction.Promote() at System.Transactions.TransactionInterop.ConvertToOletxTransaction(Transaction transaction) at System.Transactions.TransactionInterop.GetDtcTransaction(Transaction transaction) at System.Messaging.MessageQueue.StaleSafeReceiveMessage(UInt32 timeout, Int32 action, MQPROPS properties, NativeOverlapped* overlapped, ReceiveCallback receiveCallback, CursorHandle cursorHandle, IntPtr transaction) at System.Messaging.MessageQueue.ReceiveCurrent(TimeSpan timeout, Int32 action, CursorHandle cursor, MessagePropertyFilter filter, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType) at System.Messaging.MessageQueue.Receive(TimeSpan timeout, MessageQueueTransactionType transactionType) at NServiceBus.Transports.Msmq.MsmqDequeueStrategy.ReceiveMessage(Func`1 receive) in c:\BuildAgent\workf8c64a6e8a2d7c\src\NServiceBus.Core\Transports\Msmq\MsmqDequeueStrategy.cs:line 313
一些其他注意事项:
- 错误的 ApplicationPools 身份和 Windows 服务的登录用户是相同的。
- 这在之前确实很管用 最近重新启动,因为 Web.API 服务能够成功 处理订阅请求,并且能够仅发布消息 很好(尽管发布不会自动使用 MSDTC,而且我们 不显式使用 TransactionScope)。自从本地重启后,我们 如果订阅请求消息存在,只需得到上述错误 在任一 Web.API 发布者的输入队列中。
- 我已经使用了 procmon.exe 和 MSDTC 跟踪,但没有发现任何有用的东西。典型的事件查看器日志也不提供任何信息。
- 所有端点都是 运行 .NET 4.5 和 NServiceBus 4.6
- 我们不能 在任何其他环境中重新创建它。
以下对话的补充说明
- 抛出异常的线程是纯NServiceBus订阅管理,涉及"my"个none个代码。当应用程序池按需启动 w3wp.exe 工作进程时,NSB 会生成一个应用程序不知道的工作线程来处理订阅请求。它 应该 只能跨发布者的输入队列和订阅存储工作,我也在使用 MSMQ,在另一个队列中(即不涉及其他服务器)据我所知)。
- 网站的 "code" 在重新启动后没有变化,应用程序池在重新启动之前停止并重新启动了几次,没有问题。
不是真正的答案,但评论太长了。
您的操作的哪一部分需要 DTC?分布式事务会在需要时自动登记,通常是在您与两个不同的支持 DTC 的基础设施(例如 MSMQ 和数据库)对话时。
您说您通过 DTC 跟踪进行了测试——您是说 DTC Ping 吗?您是否通过在两台机器(或所有机器,如果交易中涉及多于两台机器)上使用 运行 进行测试? DTC 工具非常深奥,其输出可能令人困惑。
另外,如果它在重启前确实有效,是否可以重启重置防火墙设置?防火墙是 DTC 问题的常见原因。
此外,我假设您检查并重新检查了本地机器上的 DTC 设置?您是否确保将 MSMQ 队列设置为事务性队列?
来自您的评论:
Note that this particular failure occurs when attempting to dequeue a message from a local private MSMQ queue [...]
堆栈跟踪显示它正在做的就是这些,但我怀疑它在尝试出队时也在尝试征集多个服务器之间的事务。见下文。
Why MSDTC? It's the original way to support exactly-once messaging in NServiceBus (see here).
是的,但我要问的是为什么特定操作 需要 分布式事务。如果处理程序所做的只是从队列中读取和(例如)将输出写入控制台,则 MSDTC 将永远不会被征用,即使处理程序被包装在事务范围内也是如此。它将简单地使用本地事务从队列中读取。升级到分布式事务是自动的,只有在需要支持多个基础架构时才会发生。
因此,如果您最近在将数据写入新数据库服务器的处理程序中部署了代码,您可能会遇到故障,因为您现在正在征用包含新服务器的事务,这可能是发生故障的地方.
所以确定分布式事务涉及的所有服务器是第一步。下一步是检查所有相关服务器上的 DTC 设置。如果 DTC 设置不是问题,我建议使用 DTCPing 测试服务器之间的通信。 NServiceBus documentation 有一些关于使用 DTCPing 的很好的说明。
"fixed" 这对我们在生产环境中的作用是将应用程序池身份用户添加到服务器上的本地管理员组。不幸的是,我们没有时间确定哪些设置需要安全设置,因为这在其他类似服务器中不是必需的配置。此外,从安全角度来看,这不是最理想的解决方案,但在我们的特定情况下,我们愿意接受它。