我有一个ASP.NET应用程序,它通过创建和写入自定义性能计数器来跟踪统计信息。有时,我会在错误日志中看到指示计数器无法打开,因为它们已在当前进程中使用过。我认为这是由于我的.NET appdomain已在同一个w3wp.exe进程中重置。当我的应用程序域被回收后,如何避免这些错误并重新建立与性能计数器的连接?
柜台建设:
PerformanceCounter pc = new PerformanceCounter();
pc.CategoryName = category_name;
pc.CounterName = counter_name;
pc.ReadOnly = false;
pc.InstanceLifetime =
PerformanceCounterInstanceLifetime.Process;
pc.InstanceName = instance_name;
专柜使用:
pc.Increment()
[2009年3月26日更新] 收到的错误消息是:
实例'_lm_w3svc_1_root_myapp'已经存在且具有生命周期。在删除它或使用它的进程退出之前,它不能重新创建或重用。 已存在具有生命周期的过程。
我尝试通过初始化性能计数器并在瞬态AppDomain中写入其中一个来复制控制台应用程序中的异常。然后我卸载AppDomain并在第二个Appdomain中再次执行(相同的过程)。他们都成功了。我现在不确定究竟是什么原因,我在ASP.NET中关于AppDomain回收的假设似乎是假的。
答案 0 :(得分:5)
使用process based WCF performance counters时,应用程序日志中也可能会遇到上述错误。这种情况的症状是应用程序事件日志中的三个错误块:
未加载效果计数器 类别名称:ServiceModelService 3.0.0.0
柜台名称:电话
例外:System.InvalidOperationException:Instance' abc @ def | service.svc'已存在具有生命周期的过程。在删除它或使用它的进程退出之前,不能重新创建或重用它。
这始终在系统事件日志中的以下信息消息之后立即发生:
进程ID为' nnnn'的工作进程服务应用程序池' MyAppPool'已请求回收,因为工作进程已达到其允许的处理时间限制。
这会导致此服务的性能监视器计数器变得不可用,显然是几个小时。
ServiceModelService 3.0.0.0
版本号将depend on the version of .NET you are using(这是使用.NET 3.5测试的)。
故障由工人流程达到其处理时限触发,此时必须回收。这是在IIS应用程序池回收设置(IIS 6.0及更高版本,因此Windows Server 2003及更高版本)中设置的。回收工作进程会导致基于新进程的性能计数器名称与旧进程冲突,从而产生错误。这是因为IIS使用overlapped recycling,其中要终止的工作进程在新工作进程启动之前一直保持运行。
(在Windows Server 2003上测试= IIS 6.0)
web.config
部分的<system.serviceModel>
:<diagnostics performanceCounters="All" />
W3SVC
信息事件的事件查看器系统日志中所示)。System.ServiceModel 3.0.0.0
的应用程序日志中出现一批三个错误。Hotfix KB981574取代了修补程序KB971601。后一个修补程序描述了问题:
FIX:监视应用程序的性能计数器在应用程序退出并重新启动时停止响应,并且在运行.NET Framework 2.0的计算机上收到System.InvalidOperationException异常
应用前一个修补程序无法解决问题。应用后一个修补程序会导致应用程序池错误。
可以创建service host factory that exposes a custom service host:
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace MyNamespace
{
public class WebFarmServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(
Type serviceType, Uri[] baseAddresses)
{
return new WebFarmServiceHost(serviceType, baseAddresses);
}
}
public class WebFarmServiceHost : ServiceHost
{
public WebFarmServiceHost(
Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
protected override void ApplyConfiguration()
{
base.ApplyConfiguration();
Description.Name = "W3wp" + Process.GetCurrentProcess().Id +
Description.Name;
}
}
}
请参阅服务标记.svc
文件中的工厂:
<%@ ServiceHost Language="C#" Debug="true" Factory="MyNamespace.WebFarmServiceHostFactory" Service="WcfService1.Service1" CodeBehind="Service1.svc.cs" %>
不幸的是,虽然这会使问题的发生频率降低,但仍然会发生(尽管我已经没有测量到准确的统计数据,但是大约会减少30倍左右。)
一个简单的调整似乎可以完全解决问题,就是在base.ApplyConfiguration();
之前添加一个睡眠命令:
Thread.Sleep(1);
这仅针对每个工作进程回收一次,因此对服务性能的影响可以忽略不计。您可能必须提高此值(您可以将其设置为可配置),尽管1ms的最小设置对我有效(关于此命令实际上睡了多久的争论)。
在IIS中有一个DisallowOverlappingRotation
Metabase Property。这个can be set as follows(给出了MyAppPool
应用程序池的示例):
cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET w3svc/AppPools/MyAppPool/DisallowOverlappingRotation TRUE
当由于缺少IIS重叠回收而导致工作进程回收时,解决方案#3将cause your site to be down longer。
对于基本Web服务的soapUI加载测试,使用5个线程,每秒使用100次以上的事务,并且“冻结”#39;每次工人流程回收时,新交易被阻止的地方显而易见。当测试更复杂的Web服务时,这种冻结会更长(8秒以上)。
解决方案#2没有产生这样的阻塞,在循环过程中响应流畅,并且没有产生perfmon冲突错误。
对于不要求低延迟的Web服务,可以使用解决方案#3。如果您知道负载分布和一天中的安静时间,您甚至可以在设定的时间将回收设置为每天(这可以在IIS中的相同选项卡中完成)。如果使用网络农场,这甚至可能会错开。
对于无法忍受此类延迟的网络服务,似乎解决方案#2是最佳方式。
答案 1 :(得分:2)
结果是存在两个AppDomains存在重叠,两个AppDomain都具有相同的instance_name
值。
然而,并非所有问题都得到解决。我通过将进程ID作为实例名称的一部分包含在我的代码中更正了此问题。但它似乎引入了另一个问题 - 我认为是一个进程范围的性能计数器似乎永远不会在没有重新启动计算机的情况下消失。 (这可能是我的错误,所以YMMV)。
这是我创建实例名称的例程:
private static string GetFriendlyInstanceName()
{
string friendlyName = AppDomain.CurrentDomain.FriendlyName;
int dashPosition = friendlyName.IndexOf('-');
if (dashPosition > 0)
{
friendlyName = friendlyName.Substring(0, dashPosition);
}
friendlyName = friendlyName.TrimStart('_');
string processID = Process.GetCurrentProcess().Id.ToString();
string processName = Process.GetCurrentProcess().ProcessName;
string instanceName = processName + " " + processID + " " + friendlyName.Replace('/', '_').Trim('_').Trim();
return instanceName;
}
答案 2 :(得分:0)
我不是自定义计数器的专家,但根据您提供的信息,我认为考虑到一些代码在添加域即将被回收时尝试使用计数器的可能性值得一试。在与dispose或析构函数相关的任何事情中寻找计数器的使用。
答案 3 :(得分:0)
如果您懒洋洋地创建性能计数器,则可能是线程问题。在进程回收之后,如果同时发生两次页面命中(这不会让我感到惊讶),那么您的性能创建调用可能会多次运行。一方面,您可以安全地忽略此错误。但是如果您想要消除它,我建议您使用锁定语句(如
)包装性能计数器代码生成lock (this.lockObject)
{
//Create performance counter
}
答案 4 :(得分:0)
我遇到了类似的问题: 多实例,Process LifeTime计数器无法在Visual Studio中创建多次,但这是因为我打开了PerfMon!
我花了一些时间意识到这一点。
答案 5 :(得分:0)
IIS保证您的第一个AppDomain在启动第二个AppDomain之前没有关闭,特别是当您手动或自动回收它时,如果您将应用程序池回收“禁用重叠回收”属性设置为false(默认)。
如果是共享托管,您可以在web.config文件中定义。