我的公司正在使用 Azure 服务总线中继将敏感数据的摘要汇总到 Azure 托管的应用程序中。我们注意到在预生产服务器上,在处理前几个请求后,托管 ServiceHost 实例的进程的 CPU 利用率跃升至 70-90% 并保持在那里。ServiceHost 通常在 Windows 服务中自托管,但我们也有一个 WPF 应用程序,我们在其下运行它以用于各种设置和测试场景,并且我们可以在两者上重现此行为。我们无法在我们的开发环境中重现此行为。
我已经查看了代码并将其与 MSDN 上的示例进行了比较,在我看来它们看起来相当。这是精简版:
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;
this.serviceBusUri = ...;
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(...,...);
ContractDescription contractDescription = ContractDescription.GetContract(typeof(IOurServiceProxy), typeof(OurServiceProxy));
NetTcpRelayBinding binding = new NetTcpRelayBinding(EndToEndSecurityMode.Transport, RelayClientAuthenticationType.RelayAccessToken, true);
binding.ConnectionMode = TcpRelayConnectionMode.Relayed;
this.serviceEndpoint = new ServiceEndpoint(contractDescription);
this.serviceEndpoint.Address = new EndpointAddress(this.serviceBusUri);
this.serviceEndpoint.Binding = binding;
this.serviceEndpoint.Behaviors.Add(sharedSecretServiceBusCredential);
this.host = new ServiceHost(typeof(OurServiceProxy), this.serviceBusUri);
this.host.Description.Endpoints.Add(this.serviceEndpoint);
this.host.Open();
this.host.Faulted += OnFaulted;
我们从未看到OnFaulted
事件处理程序被触发,并且在 CPU 跳转后继续处理请求。主机应用程序的 WPF 版本有一个按钮,可以通过调用断开与服务总线的连接this.host.Close()
,一旦断开连接,CPU 立即返回空闲状态。
我已经做了一个跟踪侦听器,但唯一的消息与启动SystemConnectivity.Mode
时的自动检测有关。ServiceHost
堆栈中的故障位置是对Microsoft.ServiceBus.NetworkDetector.DetectInternalConnectivityModeForAutoDetect(Uri uri)
. 错误本身被 Microsoft.ServicBus 层捕获,并且永远不会冒泡到我公司的代码中。跟踪捕获的特定异常消息是
无法连接到 net.tcp://[name_redacted].servicebus.windows.net:9350/。连接尝试持续了 00:00:01.1856021 的时间跨度。TCP 错误代码 10061:无法建立连接,因为目标机器主动拒绝它 [ip_redacted]:9350。
这是我用于跟踪的设置:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Warning, Error, Critical"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "C:\Temp\Traces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
接下来,我尝试对哪些线程正在消耗所有 CPU 进行一些分析。我从进程的内存转储开始,但认为单个快照无法为我提供有关随着时间推移发生的事情的足够信息,因此我找到了Sam Saffron 的关于生产 .Net 应用程序的 CPU 分析的博客文章。我们获取了最新版本的 cpu-analyzer 源代码并在相关服务器上运行它。所有最昂贵的堆栈System.Threading._IOCompletionCallback.PerformIOCompletionCallback
在底部都有一个签名。我的理解是在捕获过程中没有服务总线调用,所以我不确定这个线程会做什么。
我们接下来的步骤是在服务器上运行 perfmon 捕获并查看结果,看看是否有任何明显的问题出现在我们面前。我没有直接访问服务器的权限,因此需要与 SysAdmin 安排时间来进行动手分析。
有没有人知道什么可能导致这个隐藏的 CPU 峰值?在 Azure 服务总线中继或 WCF 中是否有任何已知的行为?任何建议将不胜感激。