了解 IIS 8 中 NUMA 硬件上的多核缩放

作者:Kaori Sawada

非一致性内存访问 (NUMA) 是计算机内存访问的新型设计,旨在克服对称多处理器 (SMP) 体系结构的可伸缩性限制。 在 SMP 中,每个核心将访问自己的总线和自己的 I/O 集线器。 SMP 不太适用于大量 CPU(或 CPU 核心),因为它们在访问共享总线方面具有很高的竞争力。

NUMA 旨在通过限制任何一条内存总线上可以存在的 CPU 数量并通过高速互连将其连接,来缓解此类瓶颈。 为了利用这些功能,IIS 8(Windows Server 2012 的一部分)及更高版本提供了用于增强 NUMA 硬件性能的功能。 这使得 IIS 能够智能地将工作进程关联到 NUMA 节点并提供更好的 CPU 利用率。

为了向管理员提供较高控制度,IIS 8 提供了以下四个新功能/选项,可在支持 NUMA 硬件的服务器上发挥作用:

  • 处理器关联
  • 关联模式
  • 最佳 NUMA 选择
  • Web 花园

处理器关联

处理器关联并不是一个新功能,但它在 IIS 8 中得到了增强。 smpProcessorAffinityMasksmpProcessorAffinityMask2 属性自 IIS 7 起可用,允许管理员将应用程序池关联到特定核心。 在 IIS 8 中它们的用途并未改变,但 IIS 8 中引入了以下新架构元素来支持 64 个以上的逻辑处理器 (LP):

<element name="cpu">
 ...
 <attribute name="smpAffinitized" type="bool" defaultValue="false"/>
 <attribute name="smpProcessorAffinityMask" type="uint" defaultValue="4294967295"/>
 <attribute name="smpProcessorAffinityMask2" type="uint" defaultValue="4294967295"/>
 <attribute name="processorGroup" type="int" defaultValue="0" validationType="integerRange"
 validationParameter="0,2147483647"/>
 ...
</element>

* 突出显示 IIS 8 的更改

注意

为了支持 64 个以上的 LP,引入了一个新概念:处理器组。 任何具有 64 个以上 LP 的计算机都必然具有多个处理器组。 单个处理器组是一组静态 LP,并被视为单个计划实体。 当操作系统启动时,它会创建处理器组并向其分配逻辑处理器。 处理器组从 0 开始编号。

由于 smpProcessorAffinityMasksmpProcessorAffinityMask2 提供 64 位(各提供 32 位),因此 processorGroup 属性可用于在最多 64 个核心的系统上关联应用程序池。 这两个关联掩码用于配置十进制处理器掩码,十进制处理器掩码指示应用程序池中的工作进程应该绑定到哪个 CPU。 例如,如果计算机有 64 个处理器,并且你想要启用第 8、15、26、32、40、48 和 60 个处理器,则可以如下所示计算十六进制处理器掩码。

处理器标识从 0 开始从右到左设置,因此在二进制中,可以将前 32 个处理器中的处理器 8、15、26 和 32 标识为:

1000 0010 0000 0000 0100 0000 1000 0000

该数字在转换为十进制后即为 smpProcessorAffinityMask:

0x82004080

还可以将第二组 32 个处理器中的处理器 40、48 和 60 标识为:

0000 1000 0000 0000 1000 0000 1000 0000

该数字在转换为十进制后即为 smpProcessorAffinityMask2:

0x8008080

由于这两个关联掩码的类型为 uint,即无符号 32 位整数,因此它们总共提供 64 个可寻址位,允许你指定最多 64 个处理器。 为了支持将应用程序池关联到 1 个以上的处理器组或存在 64 个以上的处理器,processorGroup 属性代表了这种情况。 如果引用编号为 0 的 processorGroup,则相应的 AffinityMask 值将应用于编号为 0 到 63 的第一组。 如果引用 processorGroup 1,则掩码值将应用于第二个处理器组,其编号为 64 到 127。 只能指定一个处理器组来将应用程序池与 LP 关联。 以下示例显示掩码值仅应用于第二个处理器组,即组 1。 此应用程序池中的任何工作进程都不会在第一个处理器组(即组 0)中的 LP 上运行。

下面是 applicationHost.config 的配置示例。

<applicationPools>
   <add name="DefaultAppPool">
      <cpu smpAffinitized="true" smpProcessorAffinityMask="82004080" 
      smpProcessorAffinityMask2="8008080" processorGroup="1" />
   </add>
</appricationPools>

注意

即使处理器中的 LP 少于 64 个,也可以配置 2 个以上的处理器组。

https://msdn.microsoft.com/library/ff542298(VS.85).aspx

在这种情况下,smpProcessorAffinityMask 和 smpProcessorAffinityMask2 属性的某些位将被忽略。

下图显示了如何在应用程序池高级配置对话框中配置掩码。

Screenshot that shows the Advanced Settings dialog box. Processor Affinity Mask and Processor Group are highlighted.

使用此配置时,ApplicationPools 将硬关联,这意味着不会对其他 NUMA 节点产生影响。 测试表明,以每秒请求数 (RPS) 衡量,硬关联比软关联提供更高的吞吐量。

注意

仅当与 AffinityMasks 一起使用时,才会遵循 processorGroup,以手动将进程关联到核心。

关联模式

将进程关联到核心或 NUMA 节点时,可以使用两种关联模式:

  1. 硬关联。 进程关联到一个核心(或组成 NUMA 节点的核心),并且该进程的所有线程都由关联的核心执行。 无论其他核心是否有额外的 CPU 周期,线程都无法由系统上的其他核心执行。 线程包含在关联核心内。
  2. 软关联。 进程关联到一个核心(或组成 NUMA 节点的核心)作为“首选核心”。 当一个线程即将被计划执行时,首先考虑“首选核心”,但是,根据系统上其他核心的负载和可用性,该线程可能会被调度给系统上的其他核心。 这种行为通常被描述为“溢出”效应,其中线程“溢出”到其他非软关联的核心。

IIS 8 中引入了以下用于配置关联模式的新架构元素:

<element name="cpu">
 ...
 <attribute name="numaNodeAffinityMode" type="enum" defaultValue="Soft">
 <enum name="Soft" value="0" />
 <enum name="Hard" value="1" />
 </attribute>
</element>

管理员还可以使用 Internet Service Manager 配置 numaNodeAffinityMode 属性。

Screenshot that shows the Advanced Settings dialog box. NUMA Node Affinity Mode is set to Soft and is highlighted.

默认情况下,应用程序池是软关联的,因为它对于大多数方案而言是一种更“宽容”的配置。 如果足够先进并且可以智能地配置 smpProcessorAffinityMasksmpProcessorAffinityMask2 属性,则根据系统的节点布局配置硬/软关联可以提高性能。

最佳 NUMA 选择

默认情况下,Windows 使用简单的“轮循”算法将每个进程分配到系统中的下一个 NUMA 节点。 这可确保在默认情况下,任何给定进程的线程尽可能在同一 NUMA 节点中运行。 但是,IIS 8 启用了另一种调度算法,以最大程度地减少对远程 NUMA 节点上内存的访问。 最佳 NUMA 选择是指 IIS 8 选择应该为即将实例化的工作进程提供更好性能的 NUMA 节点的功能。 IIS 8 中有两个选项可用于进行此配置:

  1. MostAvailableMemory。 WAS 启动的工作进程的调度算法,会将进程调度给可用内存最多的节点。 这有助于最大程度地减少对远程 NUMA 节点上内存的访问。 第一个工作进程是根据哪个 NUMA 节点拥有最多可用(空闲)内存选择的。 其余工作进程以轮循方式关联。

    注意

    numaNodeAffinityMode 属性仅适用于 MostAvailableMemory

  2. WindowsScheduling。 默认情况下,操作系统在 NUMA 系统上使用“轮循”算法将每个进程分配到系统中的下一个 NUMA 节点。 工作进程均匀分布,因为 Windows 根据这种“轮循”算法选择 NUMA 节点,并将进程软关联到 NUMA 节点。

    注意

    numaNodeAffinityMode 属性不适用于 WindowsScheduling,因为这不是一种 IIS 实现,而本身是 Windows 实现。

使用新的架构选项配置这些选项:

<element name="cpu">
 ... 
 <attribute name="numaNodeAssignment" type="enum"   defaultValue="MostAvailableMemory">
 <enum name="MostAvailableMemory" value="0"/>
 <enum name="WindowsScheduling" value="1"/>
 </attribute >
 ... 
</element>

管理员还可以使用 Internet Service Manager 配置 numaNodeAssignment 属性。

Screenshot that shows the Advanced Settings dialog box. NUMA Node Assignment is highlighted.

工作原理

假设某个配置包含 8 个 NUMA 节点,以及由 4 个进程组成的 Web 花园。 如果 numaNodeAssignment 属性设置为 MostAvailableMemory,并且选择 NUMA 节点 2 作为 4 个进程中第一个进程的最佳 NUMA 节点并关联到该节点,则后续进程将依次关联到 NUMA 节点 3、节点 4 和节点 5:

NUMA0 NUMA1 NUMA2 NUMA3 NUMA4 NUMA5 NUMA6 NUMA7
IIS w3wp IIS w3wp IIS w3wp IIS w3wp

同样,如果为 4 个进程中的第一个进程选择 NUMA 节点 6,则后续进程将依次关联到 NUMA 节点 7、0 和 1:

NUMA0 NUMA1 NUMA2 NUMA3 NUMA4 NUMA5 NUMA6 NUMA7
IIS w3wp IIS w3wp IIS w3wp IIS w3wp

Web 花园

IIS 8 及更高版本上的 Web 花园行为也发生了一些变化。 在 IIS 7.5(随 Windows Server 2008 R2 一起提供)上,maxProcesses 属性的值从 1 开始,而在 IIS 8 中,该值现在从 0 开始(不过默认值仍然是 1!)。 这是它在架构中的外观:

<element name="processModel">
 ...
 <attribute name="maxProcesses" type="uint" defaultValue="1" validationType="integerRange"
 validationParameter="0,2147483647" />
 ... 
</element>

当然,也可以通过 GUI 进行配置:

Screenshot that shows the Advanced Settings dialog box. Maximum Worker Processes is set 1 and is highlighted.

当此配置在非 NUMA 硬件上设置为 0 时,将使用默认值 1。 在 NUMA 硬件上设置为 0 时,IIS 将启动与系统上的 NUMA 节点一样多的工作进程,以便工作进程和 NUMA 节点之间存在 1:1 的关联。 在此类系统上,应将 maxProcesses 值设置为 0 以实现最佳性能。