应用程序池的 CPU 设置 <cpu>

概述

<applicationPools> 集合中 <add> 元素的 <cpu> 元素可配置将在应用程序池中使用的 CPU 使用参数和 CPU 操作的值。

NUMA 支持

非一致性内存访问 (NUMA) 是一种基于硬件的方法,可将处理器关联到其各自的专用内存。 NUMA 用于提高处理器速度,作为多处理器支持的传统对称多处理器 (SMP) 模型的替代方案。 可以设置 IIS 8 及更高版本以在 NUMA 上分发和关联其进程。 在 CPU 元素中,numaNodeAssignment 属性和 numaNodeAffinityMode 属性对 NUMA 的使用进行了配置,前者可使 IIS 在 IIS 工作进程即将启动时识别出最佳的 NUMA 节点,后者则决定 IIS 工作进程的线程如何关联到 NUMA 节点。 还可使用 processModel 元素的 MaxProcesses 属性配置 NUMA,当该属性设置为 0 时,指定 IIS 自动运行与 NUMA 节点数量相同的工作进程。 有关详细信息,请参阅 NUMA 硬件上的 IIS 8.0 多核缩放

仅当 IIS 在 NUMA 硬件上运行时,才能在“高级设置”对话框中设置 NUMA 选择逻辑和关联类型

兼容性

版本 说明
IIS 10.0 <cpu> 元素在 IIS 10.0 中未进行修改。
IIS 8.5 <cpu> 元素在 IIS 8.5 中未进行修改。
IIS 8.0 action 属性添加了两个枚举值,用于定义限制行为。 添加了 processorGroup 属性,用于定义所使用的处理器组的数量。 添加了 numaNodeAssignmentnumaNodeAffinityMode 属性,用于指定 NUMA 节点的行为。
IIS 7.5 <cpu> 元素在 IIS 7.5 中未进行修改。
IIS 7.0 <cpu> 元素是在 IIS 7.0 中引入的。
IIS 6.0 <cpu> 元素取代了 IIS 6.0 IIsApplicationPools 元数据库属性的部分内容

安装

<applicationPools> 集合包含在 IIS 7 及更高版本的默认安装中。

操作方式

如何编辑 CPU 配置设置

  1. 打开 Internet Information Services (IIS) 管理器:

    • 如果使用的是 Windows Server 2012 或 Windows Server 2012 R2:

      • 在任务栏上,单击“服务器管理器”,单击“工具”,然后单击“Internet Information Services (IIS)管理器”
    • 如果使用的是 Windows 8 或 Windows 8.1:

      • 按住 Windows 键,按字母 X,然后单击“控制面板”
      • 单击“管理工具”,然后双击“Internet Information Services (IIS)管理器”
    • 如果使用的是 Windows Server 2008 或 Windows Server 2008 R2:

      • 在任务栏上,单击“开始”,指向“管理工具”,然后单击“Internet Information Services (IIS)管理器”
    • 如果使用的是 Windows Vista 或 Windows 7:

      • 在任务栏上,单击“开始”,然后单击“控制面板”
      • 双击“管理工具”,然后双击“Internet Information Services (IIS)管理器”
  2. 在“连接”窗格中,展开服务器名称,单击“应用程序池”,然后单击要编辑的应用程序池
    Screenshot of the Application Pools screen that populates from the Connections pane.

  3. 在“操作”窗格中,单击“高级设置...”

  4. 在“高级设置”对话框中,单击要编辑的 CPU 属性,对该对话框的属性值部分中的值进行编辑,然后单击“确定”。 例如,可以将“限制操作”更改为“NoAction”、“KillW3wp”、“Throttle”或“ThrottleUnderLoad”
    Screenshot of the Advanced Settings dialog box's Throttle Under Load section.

如何配置 IIS 以使用非一致性内存访问 (NUMA) 硬件

  1. 在任务栏上,单击“服务器管理器”,单击“工具”,然后单击“Internet Information Services (IIS)管理器”

  2. 在“连接”窗格中,展开服务器名称,然后单击“应用程序池”

  3. 在“应用程序池”窗格中,选择要为 NUMA 配置的池

  4. 在“操作”窗格中,选择“高级设置”

  5. 在“进程模型”中,将“最大工作进程数”设置为 0

    Screenshot of the Process Model section with the Maximum Worker Processes field set to 0.

  6. 在“CPU”下,设置“processorGroup”、“numaNodeAffinityMode”和“numaNodeAssignment”

  7. 单击“确定”。

配置

特性

属性 说明
action 可选 enum 属性。 配置当工作进程超出其配置 CPU 限制时 IIS 执行的操作。 action 属性基于每个应用程序池配置。

action 属性可为以下值之一。 默认值为 NoAction

说明
NoAction 超出 CPU 限制时不执行任何操作。 事件日志中将写入一个警告。

数值为 0

KillW3wp 超出 CPU 限制的应用程序池工作进程将被强制关闭。

数值为 1

Throttle CPU 消耗限制为在“限制”中设置的值。 不使用“限制间隔”,并生成事件日志条目。

数值为 2

ThrottleUnderLoad 仅当 CPU 上存在争用时,CPU 消耗才会受到限制。 不使用“限制间隔”,并生成事件日志条目。

数值为 3

limit 可选 uint 属性。 配置允许应用程序池中的工作进程在一段时间内消耗的最大 CPU 时间百分比(以 0.001% 为单位),如 ResetInterval 属性所示。 如果超出 limit 属性设置的限制,则事件日志中将写入一个事件,并触发一组可选事件。 这些可选事件由 action 属性确定。

注意:在 IIS 8.5 及更高版本中,在 IIS 管理器的 CPU 窗格中设置 limit(以百分比为单位)。 在 IIS 8.0 中,在 IIS 管理器的 CPU 面板中设置 limit(以 0.001% 为单位)。 对于这两种情况,applicationHost.config 中的 limit 属性均以 0.001% 为单位。

默认值为 0,即禁用 CPU 限制。
numaNodeAffinityMode 可选 enum 属性。 指定如何在节点的核心上计划与 NUMA 节点关联的进程的线程。

numaNodeAffinityMode 属性可为以下值之一。 默认值为 Soft

说明
Soft 只要进程关联的 NUMA 节点中的核心可用,该进程的所有线程都将计划到这些核心上。 但是,如果计划程序无法将进程计划到其所关联的节点的核心上,则可以将进程计划到另一个 NUMA 节点的核心上。

数值为 0

Hard 关联到 NUMA 节点的进程的任何线程都将被计划到该节点的核心上,并且只能计划到这些核心上。 进程的任何线程都不会被计划到另一个 NUMA 节点的核心上。

数值为 1

numaNodeAssignment 可选 enum 属性。 指定 IIS 如何确定将进程关联到哪个 NUMA(非一致性内存访问)节点。 NUMA 节点包含共享单个内存组的核心集群。 仅当 NUMA 节点可用时,此属性在 CPU 高级设置中才可用。

numaNodeAssignment 属性可为以下值之一。 默认值为 Most Available Memory

说明
Most Available Memory 该进程将被分配到具有最多可用内存的 NUMA 节点。

数值为 0

Windows Scheduling Windows 计划将确定将进程分配到的 NUMA 节点。

数值为 1

processorGroup 可选 int 属性。 使用的处理器组的数量(从零开始)。 一个处理器组包含多个核心。 仅当服务器具有多个处理器组时,“CPU 高级设置”中的“处理器组”属性才可用。

默认值为 0,即使用一个处理器组。
resetInterval 可选 timeSpan 属性。 指定应用程序池上 CPU 监视和限制的重置周期(以分钟为单位)。 当自上次重置进程记帐以来经过的分钟数等于此属性指定的分钟数时,IIS 会重置日志记录和限制间隔的 CPU 计时器。

重要提示:resetInterval 值必须大于日志记录操作之间的间隔时间,否则 IIS 将在日志记录之前重置计数器,并且不会进行进程记帐

注意:由于 IIS 中的进程记帐使用 Windows 作业对象来监视整个进程的 CPU 时间,因此进程记帐将仅记录和限制在独立于 IIS 的进程中的应用程序

默认值为 00:05:00
smpAffinitized 可选布尔属性。 指定分配给应用程序池的特定工作进程是否也应分配给给定的 CPU。 该属性与 smpProcessorAffinityMask 和 smpProcessorAffinityMask2 属性一起使用

默认值为 false
smpProcessorAffinityMask 可选 uint 属性。 指定多处理器计算机的十六进制处理器掩码,用于指示应用程序池中的工作进程应绑定到哪个 CPU。 在此属性生效之前,必须将应用程序池的 smpAffinitized 属性设置为 true

注意:在 64 位计算机上,smpProcessorAffinityMask 属性包含处理器掩码的低位 DWORD,smpProcessorAffinityMask2 属性包含处理器掩码的高位 DWORD。 在 32 位计算机上,smpProcessorAffinityMask2 属性无效

如果将该值设置为 1(对应于二进制的 00000000000000001),应用程序池中的工作进程仅在第一个处理器上运行。 如果将该值设置为 2(对应于二进制的 0000000000000010),工作进程仅在第二个处理器上运行。 如果将该值设置为 3(对应于二进制的 0000000000000011),工作进程将在第一个和第二个处理器上运行。

注意:请勿将此属性设置为 0。 这样做会禁用对称多处理 (SMP) 关联性并产生错误条件。 这意味着在一个 CPU 上运行的进程在其整个生命周期中不会一直与该 CPU 关联。

默认值为 4294967295
smpProcessorAffinityMask2 可选 uint 属性。 指定 64 位多处理器计算机的高位 DWORD 十六进制处理器掩码,用于指示应用程序池中的工作进程应绑定到哪个 CPU。 在此属性生效之前,必须将应用程序池的 smpAffinitized 属性设置为 true

注意:在 64 位计算机上,smpProcessorAffinityMask 属性包含处理器掩码的低位 DWORD,smpProcessorAffinityMask2 属性包含处理器掩码的高位 DWORD。 在 32 位计算机上,smpProcessorAffinityMask2 属性无效

默认值为 4294967295

子元素

无。

配置示例

以下配置示例配置一个名为 DefaultAppPool 的应用程序池,将 CPU 设置为 50%,并设置了一个终止工作进程的操作,重置时间间隔为 10 分钟。

<applicationPools>
   <add name="DefaultAppPool">
     <cpu limit="50000" action="KillW3wp" resetInterval="00:10:00" />
   </add>
   <applicationPoolDefaults>
     <processModel identityType="NetworkService" />
   </applicationPoolDefaults>
</applicationPools>

代码示例

以下代码示例配置默认应用程序池,使其在工作进程超出 CPU 限制时终止工作进程,并将重置时间间隔配置为四分钟。

AppCmd.exe

appcmd.exe set config -section:system.applicationHost/applicationPools /[name='DefaultAppPool'].cpu.action:"KillW3wp" /commit:apphost

appcmd.exe set config -section:system.applicationHost/applicationPools /[name='DefaultAppPool'].cpu.resetInterval:"00:04:00" /commit:apphost

注意

使用 AppCmd.exe 配置这些设置时,必须确保将 commit 参数设置为 apphost。 这会将配置设置提交到 ApplicationHost.config 文件中的相应位置部分。

C#

using System;
using System.Text;
using Microsoft.Web.Administration;

internal static class Sample
{
   private static void Main()
   {
      using (ServerManager serverManager = new ServerManager())
      {
         Configuration config = serverManager.GetApplicationHostConfiguration();
         ConfigurationSection applicationPoolsSection = config.GetSection("system.applicationHost/applicationPools");
         ConfigurationElementCollection applicationPoolsCollection = applicationPoolsSection.GetCollection();
         ConfigurationElement addElement = FindElement(applicationPoolsCollection, "add", "name", @"DefaultAppPool");

         if (addElement == null) throw new InvalidOperationException("Element not found!");

         ConfigurationElement cpuElement = addElement.GetChildElement("cpu");
         cpuElement["action"] = @"KillW3wp";
         cpuElement["resetInterval"] = TimeSpan.Parse("00:04:00");

         serverManager.CommitChanges();
      }
   }

   private static ConfigurationElement FindElement(ConfigurationElementCollection collection, string elementTagName, params string[] keyValues)
   {
      foreach (ConfigurationElement element in collection)
      {
         if (String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase))
         {
            bool matches = true;
            for (int i = 0; i < keyValues.Length; i += 2)
            {
               object o = element.GetAttributeValue(keyValues[i]);
               string value = null;
               if (o != null)
               {
                  value = o.ToString();
               }
               if (!String.Equals(value, keyValues[i + 1], StringComparison.OrdinalIgnoreCase))
               {
                  matches = false;
                  break;
               }
            }
            if (matches)
            {
               return element;
            }
         }
      }
      return null;
   }
}

VB.NET

Imports System
Imports System.Text
Imports Microsoft.Web.Administration

Module Sample
   Sub Main()
      Dim serverManager As ServerManager = New ServerManager
      Dim config As Configuration = serverManager.GetApplicationHostConfiguration
      Dim applicationPoolsSection As ConfigurationSection = config.GetSection("system.applicationHost/applicationPools")
      Dim applicationPoolsCollection As ConfigurationElementCollection = applicationPoolsSection.GetCollection
      Dim addElement As ConfigurationElement = FindElement(applicationPoolsCollection, "add", "name", "DefaultAppPool")

      If (addElement Is Nothing) Then
         Throw New InvalidOperationException("Element not found!")
      End If

      Dim cpuElement As ConfigurationElement = addElement.GetChildElement("cpu")
      cpuElement("action") = "KillW3wp"
      cpuElement("resetInterval") = TimeSpan.Parse("00:04:00")

      serverManager.CommitChanges()
   End Sub

   Private Function FindElement(ByVal collection As ConfigurationElementCollection, ByVal elementTagName As String, ByVal ParamArray keyValues() As String) As ConfigurationElement
      For Each element As ConfigurationElement In collection
         If String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase) Then
            Dim matches As Boolean = True
            Dim i As Integer
            For i = 0 To keyValues.Length - 1 Step 2
               Dim o As Object = element.GetAttributeValue(keyValues(i))
               Dim value As String = Nothing
               If (Not (o) Is Nothing) Then
                  value = o.ToString
               End If
               If Not String.Equals(value, keyValues((i + 1)), StringComparison.OrdinalIgnoreCase) Then
                  matches = False
                  Exit For
               End If
            Next
            If matches Then
               Return element
            End If
         End If
      Next
      Return Nothing
   End Function


End Module

JavaScript

var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager');
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST";
var applicationPoolsSection = adminManager.GetAdminSection("system.applicationHost/applicationPools", "MACHINE/WEBROOT/APPHOST");
var applicationPoolsCollection = applicationPoolsSection.Collection;
var addElementPos = FindElement(applicationPoolsCollection, "add", ["name", "DefaultAppPool"]);

if (addElementPos == -1) throw "Element not found!";

var addElement = applicationPoolsCollection.Item(addElementPos);
var cpuElement = addElement.ChildElements.Item("cpu");
cpuElement.Properties.Item("action").Value = "KillW3wp";
cpuElement.Properties.Item("resetInterval").Value = "00:04:00";

adminManager.CommitChanges();

function FindElement(collection, elementTagName, valuesToMatch) {
   for (var i = 0; i < collection.Count; i++) {
      var element = collection.Item(i);
      if (element.Name == elementTagName) {
         var matches = true;
         for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
            var property = element.GetPropertyByName(valuesToMatch[iVal]);
            var value = property.Value;
            if (value != null) {
               value = value.toString();
            }
            if (value != valuesToMatch[iVal + 1]) {
               matches = false;
               break;
            }
         }
         if (matches) {
            return i;
         }
      }
   }
   return -1;
}

VBScript

Set adminManager = WScript.CreateObject("Microsoft.ApplicationHost.WritableAdminManager")
adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"
Set applicationPoolsSection = adminManager.GetAdminSection("system.applicationHost/applicationPools", "MACHINE/WEBROOT/APPHOST")
Set applicationPoolsCollection = applicationPoolsSection.Collection
addElementPos = FindElement(applicationPoolsCollection, "add", Array("name", "DefaultAppPool"))

If (siteElementPos = -1) Then
   WScript.Echo "Element not found!"
   WScript.Quit
End If

Set addElement = applicationPoolsCollection.Item(addElementPos)
Set cpuElement = addElement.ChildElements.Item("cpu")
cpuElement.Properties.Item("action").Value = "KillW3wp"
cpuElement.Properties.Item("resetInterval").Value = "00:04:00"

adminManager.CommitChanges()

Function FindElement(collection, elementTagName, valuesToMatch)
   For i = 0 To CInt(collection.Count) - 1
      Set element = collection.Item(i)
      If element.Name = elementTagName Then
         matches = True
         For iVal = 0 To UBound(valuesToMatch) Step 2
            Set property = element.GetPropertyByName(valuesToMatch(iVal))
            value = property.Value
            If Not IsNull(value) Then
               value = CStr(value)
            End If
            If Not value = CStr(valuesToMatch(iVal + 1)) Then
               matches = False
               Exit For
            End If
         Next
         If matches Then
            Exit For
         End If
      End If
   Next
   If matches Then
      FindElement = i
   Else
      FindElement = -1
   End If
End Function