代码之家  ›  专栏  ›  技术社区  ›  jlew

跨appdomain使用自定义性能计数器是

  •  5
  • jlew  · 技术社区  · 16 年前

    我有一个ASP。NET应用程序,通过创建和写入自定义性能计数器来跟踪统计信息。偶尔,我在错误日志中看到,计数器无法打开,因为它们已经在当前进程中使用过。我想这是由于我。NET应用程序域已在同一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”已存在,其生存期为进程。在将其删除或使用它的进程退出之前,无法重新创建或重用它。 已存在,其生命周期为Process。

    我试图通过初始化性能计数器并在瞬态AppDomain中写入其中一个计数器,在控制台应用程序中复制异常。然后,我卸载AppDomain,并在第二个AppDomain中再次执行此操作(同一过程)。他们俩都成功了。我现在不确定确切的原因是什么,我对ASP中AppDomain回收的假设。NET似乎是假的。

    6 回复  |  直到 6 年前
        1
  •  5
  •   SharpC Paul    12 年前

    使用时,应用程序日志中也可能出现上述错误 process based WCF performance counters 。其症状是应用程序事件日志中的三个错误块:

    未加载性能计数器。
    类别名称:ServiceModelService 3.0.0.0
    柜台名称:呼叫
    例外:系统。InvalidOperationException:实例'abc@def|service.svc已存在,其生存期为Process。在将其删除或使用它的进程退出之前,无法重新创建或重用它。

    这总是在系统事件日志中的以下信息消息之后立即发生:

    为应用程序池“MyAppPool”提供服务的进程id为“nnnn”的工作进程已请求回收,因为该工作进程已达到其允许的处理时间限制。

    这会导致此服务的性能监视器计数器不可用,显然会持续几个小时。

    这个 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上测试)

    • 创建WCF服务。
    • 添加 the following web.config <system.serviceModel> 章节:
      <diagnostics performanceCounters="All" />
    • 在“属性回收”下的服务的应用程序池属性中,将回收工作进程设置为1分钟。手动回收应用程序池没有效果,因为这不会从工作进程中创建回收请求(如事件查看器系统日志中所示 W3SVC 信息事件)。
    • 在……里面 soapUI 为WCF操作创建测试套件/测试用例/测试步骤/测试请求。
    • 将测试用例添加到soapUI中的负载测试中,或使用 loadUI ,以每秒1次的速率发出呼叫。
    • 每1分钟,工作进程将请求一次回收(在系统日志中明显可见)。每2分钟,这将导致应用程序日志中出现一批三个错误 System.ServiceModel 3.0.0.0 .
    • 在工作进程再次回收之前,该服务的性能计数器将不可用。(注意:此时将回收期设置为更高的值,以查看性能计数器不可用的时间有多长,这将实际回收进程并使计数器再次可用。)

    可能的解决方案

    解决方案1-转移注意力

    修补程序 KB981574 取代修补程序 KB971601 后一个修补程序描述了该问题:

    修复:当应用程序退出并重新启动并且您收到系统时,监视应用程序的性能计数器停止响应。正在运行的计算机上出现InvalidOperationException异常。NET Framework 2.0

    应用前一个修补程序并不能解决问题。应用后一个修补程序导致应用程序池错误。

    解决方案2-可行的解决方案

    可以创建一个 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倍,尽管我还没有测量到准确的统计数据)。

    一个似乎完全解决问题的简单调整是在之前添加一个sleep命令 base.ApplyConfiguration(); :

    Thread.Sleep(1);
    

    这只会在每个工人的流程循环中触发一次,因此对服务性能的影响可以忽略不计。您可能需要提高此值(您可以使其可配置),尽管1ms的最小设置对我来说是有效的(关于此命令实际休眠多长时间的争论)。

    解决方案3-最简单的解决方案

    在IIS中有一个 DisallowOverlappingRotation Metabase Property .这个 can be set as follows (示例如下 MyAppPool 应用程序池):

    cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET w3svc/AppPools/MyAppPool/DisallowOverlappingRotation TRUE
    

    解决方案比较

    解决方案#3将 cause your site to be down longer 当工作进程由于没有IIS重叠回收而回收时。

    在使用5个线程每秒100多个事务的基本web服务的soapUI负载测试中,每次工作进程回收时,新事务被阻止的“冻结”都会持续几秒钟。当测试更复杂的web服务时,这种冻结时间更长(8+秒)。

    解决方案#2没有产生此类阻塞,在回收过程中响应流畅,也没有产生性能冲突错误。

    结论

    对于不需要低延迟的web服务,可以使用解决方案3。如果你知道负载分布和一天中的安静时间,你甚至可以将回收设置为每天在设定的时间进行(这可以在IIS的同一个选项卡中完成)。如果使用网络农场,这甚至可能是交错的。

    对于不能容忍这种延迟的web服务,解决方案2似乎是最好的前进方向。

        2
  •  2
  •   Alan McBee    16 年前

    IIRC,IIS不会确保在启动第二个AppDomain之前关闭第一个AppDomain,特别是当您手动或自动回收它时。我认为,当启动回收时,首先实例化第二个AppDomain,一旦成功,新的传入请求就会被定向到它,然后IIS等待第一个AppDomain(正在关闭的AppDomain)完成处理它所拥有的任何请求。

    结果是,存在两个AppDomain的地方存在重叠,这两个AppDomains的值都相同 instance_name .

    然而,并非所有问题都已解决。我在代码中纠正了这个问题,将进程ID作为实例名称的一部分。但它似乎引入了另一个问题——我认为是进程范围的性能计数器似乎在不重新启动计算机的情况下永远不会消失。(这可能是我的一个bug,所以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;
        }
    
        3
  •  0
  •   eglasius    16 年前

    我不是自定义计数器的专家,但根据您提供的信息,我认为考虑到在添加域即将被回收时某些代码试图使用计数器的可能性,这是值得一试的。在与dispose或析构函数相关的任何内容中查找计数器的使用。

        4
  •  0
  •   Ender    16 年前

    如果您正在缓慢地创建性能计数器,则可能是线程问题。在流程回收后,如果同时出现两次页面点击(这并不让我感到惊讶),那么您的性能创建调用可能会运行多次。一方面,您可以安全地忽略此错误。但如果你想删除它,我建议你用一个锁语句来包装你的性能计数器代码生成,比如

    lock (this.lockObject)
    {
     //Create performance counter
    }
    
        5
  •  0
  •   Khash    15 年前

    我也遇到过类似的问题: 在Visual Studio中不能多次创建多实例、进程生命周期计数器,但这是由于我打开了PerfMon!

    我花了一段时间才意识到这一点。

        6
  •  0
  •   Manoj Patil    11 年前

    IIS保证您的第一个AppDomain在启动第二个AppDomain之前不会关闭,特别是当您手动或自动回收它时,如果您将应用程序池回收“禁用重叠回收”属性设置为false(默认值)。

    如果是共享主机,可以在web.config文件中定义。

    推荐文章