.net 在IIS进程上调试高CPU使用率 IIS进程上的高CPU使用率

.net 在IIS进程上调试高CPU使用率 IIS进程上的高CPU使用率,.net,performance,debugging,iis,.net,Performance,Debugging,Iis,我目前正在调查我们的一台生产服务器上的高CPU使用率,我被卡住了,希望这里的人能够提供帮助。将CPU使用率与入站web服务调用(WCF和REST)的数量进行比较,可以看出它们是不相关的,每当调用增加或减少时,CPU使用率似乎都会上升 设置 Windows 2012 R2服务器x64 IIS 8.5 .NET 4.5 运行我们的应用程序的单个应用程序池 00:00时自动回收应用程序池 问题 最近,我们的CPU使用率急剧增加,这种模式似乎是CPU使用率从午夜开始攀升(我回收了池),并一直攀升,直

我目前正在调查我们的一台生产服务器上的高CPU使用率,我被卡住了,希望这里的人能够提供帮助。将CPU使用率与入站web服务调用(WCF和REST)的数量进行比较,可以看出它们是不相关的,每当调用增加或减少时,CPU使用率似乎都会上升

设置
  • Windows 2012 R2服务器x64
  • IIS 8.5
  • .NET 4.5
  • 运行我们的应用程序的单个应用程序池
  • 00:00时自动回收应用程序池
问题 最近,我们的CPU使用率急剧增加,这种模式似乎是CPU使用率从午夜开始攀升(我回收了池),并一直攀升,直到池再次回收

数据 通过分析taskmanager和使用perfmon计数器,我已经能够确认消耗CPU的确实是我们的W3WP进程

我将DebugDiag 2.1配置为当CPU消耗超过50%的阈值超过10秒时,每隔10秒进行3次内存转储。(此问题之前的正常CPU使用率为5-10%)

通过使用ntsd查看转储文件,我发现有几个线程消耗了大量CPU:

0:047> !runaway
 User Mode Time
  Thread       Time
  47:2920      0 days 0:24:42.921
  49:1f1c      0 days 0:23:07.796
  52:2ed8      0 days 0:21:38.218
  54:1560      0 days 0:21:37.937
  48:273c      0 days 0:21:19.140
  59:2110      0 days 0:20:56.078
  45:2d90      0 days 0:20:35.906
...
  19:1c88      0 days 0:00:00.000
(此处仅显示一些线程) 因此,我尝试查看这些线程中发生了什么,因为这不是预期的行为。所有具有长时间运行任务的线程似乎都可以管理,但每当我尝试时!clrstack在我得到的任何一个上:

0:047> !clrstack
OS Thread Id: 0x2920 (47)
        Child SP               IP Call Site
GetFrameContext failed: 1
0000000000000000 0000000000000000 <unknown>
这让我相信线程正在等待一些资源(这是正确的吗?),这就是我真正迷路的地方! 轨迹中线的情况是:

0000009c46eaefe0 00007fff0c3b1387 00007fff0c3b1387
0000009c46eaf030 00007fff04c111d2 00007fff04c111d2, calling 00007fff04c11070
我的猜测是,一些管理的东西正在这里发生,但为什么是!那我就不工作了? 通过查看第一个帧,我看到它正在等待某个资源句柄。我看起来手柄是0xa,但我还不能确定这一点。看着把手!处理0xa ff我得到以下结果:

0:047> !handle 0xa ff
Handle 000000000000000a
  Type          File
  Attributes    0
  GrantedAccess 0x100020:
         Synch
         Execute/Traverse
  HandleCount   2
  PointerCount  65535
  No object specific information available
告诉我这指向一个文件,但什么文件,我如何从这里继续?看着其他的顶级T台线程给我同样的图片

呼救声 我知道这是一个巨大的任务,但我真的需要帮助从这里开始。我是在正确的轨道上,还是只是在黑暗中摸索? 任何帮助都将不胜感激

新闻 在我们的IT部门使用一些我觉得有趣的计数器记录一个perfMon数据集之后,我得出了一个结论:1)我们正在泄漏线程2)GC正在发疯(可能是因为泄漏)。 关于如何检测导致螺纹泄漏的原因有什么想法吗? 请参见此处的计数器:

在发现我们正在泄漏线程后,我一直在研究我们的代码,并发现了一些感兴趣的代码:

// Initialize TimerExecutionEveryMinute timer
const double timeConversion = 60 * 1000; //convert one minute to milliseconds

var timer1 = new System.Timers.Timer { Enabled = true, Interval = timeConversion };
timer1.Elapsed += TimerExecutionEveryMinute;
然后:

// Execution every minute
public static void TimerExecutionEveryMinute(object sender, EventArgs e)
{
    var jpsLogger = KernelContainer.Kernel.Get<IJpsLogger>();

    // Initialize MemBag
    MemBag.Log.ActivityIdReset(Guid.NewGuid());
    MemBag.Log.BaseType = "TimerExecution";
    MemBag.Log.BaseClass = "Timer";
    MemBag.Log.BaseMethod = "TimerExecutionEveryMinute";

    // Statistic timer job
    var t1 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "One minute timer begin");

        var t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Method.WriteDB begin");
            Method.WriteDB();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Method.WriteDB end", t2);

        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Memory.LogCurrentState begin");
            Memory.LogCurrentState();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Memory.LogCurrentState end", t2);


        //Calculates the CPU load based on samples taken at every timer step
        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    CPU load begin");
            CPULogger.LogCpu();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    CPU load end", t2);

        // Dump log information to file
        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    FileLogger.WriteAsync begin");
            FileLogger.WriteAsync();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    FileLogger.WriteAsync end", t2);

        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "One minute timer end", t1);
}
//每分钟执行一次
公共静态无效TimerExecutionEveryMinute(对象发送方,事件参数e)
{
var jpsLogger=KernelContainer.Kernel.Get();
//初始化内存包
MemBag.Log.ActivityIdReset(Guid.NewGuid());
MemBag.Log.BaseType=“TimerExecution”;
MemBag.Log.BaseClass=“计时器”;
MemBag.Log.BaseMethod=“TimerExecutionEveryMinute”;
//统计计时器作业
var t1=jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“一分钟计时器开始”);
var t2=jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“Method.WriteDB begin”);
方法WriteDB();
jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“Method.writedbend”,t2);
t2=jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“Memory.LogCurrentState begin”);
Memory.LogCurrentState();
jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“Memory.LogCurrentState end”,t2);
//根据在每个计时器步骤中采集的样本计算CPU负载
t2=jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“CPU加载开始”);
CPULogger.LogCpu();
jpsLogger.Trace.SpecializedDebug(“分析.一分钟计时器”,“CPU加载结束”,t2);
//将日志信息转储到文件
t2=jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”、“FileLogger.WriteAsync begin”);
WriteAsync();
jpsLogger.Trace.SpecializedDebug(“analysis.OneMinuteTimer”,“FileLogger.WriteAsync end”,t2);
jpsLogger.Trace.SpecializedDebug(“分析.一分钟计时器”,“一分钟计时器结束”,t1);
}

这可能是漏水的地方吗?我相信System.Timers.Timer在我每次创建事件时都会启动新线程,而且它是线程安全的,所以我会在执行代码周围创建锁,代码每分钟执行一次,以及其他写入日志文件的事情,我的论文如果对文件的访问被阻止,线程不断堆积,这将解释逻辑线程数量线性增加的原因,如

所示,我没有答案,但让我尝试给出一些提示

在你的问题中你提到

最近我们的CPU使用量急剧增加

这是否意味着该应用程序以前工作正常?如中所示,您是否意识到没有异常的CPU峰值

如果是这样,那么你需要看看最近发生了什么变化:

  • 是否为您的应用程序部署了任何新代码,特别是分配大量数据的代码

  • 是否在服务器上安装了任何更新,如果是,您是否可以对其进行审核,并检查可能提到您遇到的症状的任何Microsoft知识库文章(或者简单地搜索更新名称,查看是否有博客提到它们)

在您的情况下,垃圾收集器似乎正在失控。我要做的第一件事是查看已部署的任何新代码——可能是代码(或该代码的副作用)正在分配对象,GC的副作用将进入超速状态,以处理内存压力

考虑到这一点,为什么不下载呢
// Execution every minute
public static void TimerExecutionEveryMinute(object sender, EventArgs e)
{
    var jpsLogger = KernelContainer.Kernel.Get<IJpsLogger>();

    // Initialize MemBag
    MemBag.Log.ActivityIdReset(Guid.NewGuid());
    MemBag.Log.BaseType = "TimerExecution";
    MemBag.Log.BaseClass = "Timer";
    MemBag.Log.BaseMethod = "TimerExecutionEveryMinute";

    // Statistic timer job
    var t1 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "One minute timer begin");

        var t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Method.WriteDB begin");
            Method.WriteDB();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Method.WriteDB end", t2);

        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Memory.LogCurrentState begin");
            Memory.LogCurrentState();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    Memory.LogCurrentState end", t2);


        //Calculates the CPU load based on samples taken at every timer step
        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    CPU load begin");
            CPULogger.LogCpu();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    CPU load end", t2);

        // Dump log information to file
        t2 = jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    FileLogger.WriteAsync begin");
            FileLogger.WriteAsync();
        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "    FileLogger.WriteAsync end", t2);

        jpsLogger.Trace.SpecializedDebug("Analyses.OneMinuteTimer", "One minute timer end", t1);
}
GC.GetTotalMemory(true)