CPU 利用率会影响外部 NUMA 访问的成本吗?

xav*_*xav 22 sql-server memory numa

设想

假设我有一个带有 4 个套接字的 SQL Server,每个 NUMA 节点。每个插槽有 4 个物理内核。总共有 512 GB 的内存,因此每个 NUMA 节点有 128 GB 的 RAM。

密钥表被加载到第一个 NUMA 节点中。

假设我们从该表中读取了大量流量。如果拥有 NUMA 节点的插槽的所有物理内核的 CPU 利用率为 100%,这是否会对来自其他插槽的非本地 NUMA 访问成本产生负面影响?或者另一方面是非本地 NUMA 访问的成本与该套接字的繁忙程度无关?

我希望我的问题是有道理的。如果没有,请告诉我,我会尽力澄清。

背景

上周我们的生产服务器出现了数据库问题,我们处理的一些业务似乎比其他业务受到的影响更大。我们有一些逻辑读取的查询需要超过 1 分钟。我们查看了大约 60% 的整体 CPU 利用率。我们没有查看特定于套接字的 CPU 指标。I/O 指标是平均的。

sql*_*dle 19

一个很大的问题:-) 我将概述一些涉及的因素。在任何给定的上下文中,这些因素和其他因素可能会有所不同并产生有趣的结果。

对不起,我没能把这个缩短得多......

  1. 累积 CPU 毫秒 vs 逻辑 IO
  2. SQL Server 逻辑内存节点与物理 NUMA 节点对齐
  3. 查询工作区内存分配中的自旋锁争用
  4. 任务分配给调度程序
  5. 缓冲池中的相关数据放置
  6. 物理内存放置

  1. 累积 CPU 毫秒 vs 逻辑 IO

    我经常使用逻辑 IO(或 perfmon 术语“缓冲池页面查找”)与 CPU 利用率的关系图,以衡量工作负载的 CPU 效率并寻找容易出现自旋锁的情况。

    但是 SQL Server 会通过除页面查找和自旋锁之外的大量活动来累积 CPU 时间:

    • 计划被编译和重新编译。
    • CLR 代码被执行。
    • 执行功能。

    许多其他活动会消耗大量 CPU 时间,而不会反映在页面查找中。

    在我观察到的工作负载中,这些“非逻辑 IO 密集型但占用 CPU 资源”的活动中最主要的是排序/散列活动。

    这是有道理的:考虑一个针对没有非聚集索引的哈希表的两个查询的人为示例。这两个查询具有相同的结果集,但其中一个结果集是完全无序的,而第二个结果集按多个选定列排序。第二个查询预计会消耗更多的 CPU 时间,即使它会引用缓冲池中相同数量的页面。

    在这些帖子中,更多地了解工作区内存以及已使用了多少授予的工作区:


  1. SQL Server 逻辑内存节点与物理 NUMA 节点对齐

    默认情况下,SQL Server(因为结合了其 NUMA 感知策略)为服务器上的每个 NUMA 节点创建一个 SQLOS 内存节点。随着内存分配的增长,每个分配都由 SQLOS 内存节点之一控制。

    理想情况下,SQLOS 内存节点与物理 NUMA 节点完全对齐。也就是说,每个 SQLOS 内存节点都包含来自单个 NUMA 节点的内存,没有其他 SQLOS 内存节点也包含来自同一 NUMA 节点的内存。

    然而,这种理想情况并非总是如此。

    以下 CSS SQL Server 工程师博客文章(也包含在 Kin 的响应中)详细介绍了可能导致 SQLOS 内存节点的跨 NUMA 节点内存分配持久化的行为。发生这种情况时,性能影响可能是毁灭性的。

    对于持久的跨 NUMA 节点引用的特别痛苦的情况,有一些修复。除了这两个之外,可能还有其他人:


  1. 分配工作空间内存期间的自旋锁争用

    这是它开始变得有趣的地方。我已经描述了工作区内存中的排序和散列工作消耗 CPU,但没有反映在 bpool 查找数中。

    自旋锁争用是这种特殊乐趣的另一层。当内存从缓冲池中被窃取并分配用于查询内存授权时,内存访问将使用自旋锁进行序列化。默认情况下,这是通过在 NUMA 节点级别分区的资源进行的。因此,在针对授权窃取内存时,使用工作区内存的同一 NUMA 节点上的每个查询都可能会遇到自旋锁争用。非常重要的是要注意:这不是“每个查询一次”的争用风险,如果争用点在实际授权时就会出现。相反,它是在内存被盗取时违反授权 - 因此,如果查询使用了大部分授权,那么具有非常大的内存授权的查询将有很多机会进行自旋锁争用。

    跟踪标志 8048 通过在核心级别进一步划分资源,在缓解这种争用方面做得很好。

    微软表示“如果每个插槽有 8 个或更多内核,请考虑使用跟踪标志 8048”。但是……实际上并不是每个插槽有多少个内核(只要有多个),而是在单个 NUMA 节点上完成的工作中有多少竞争机会。

    在粘合的 AMD 处理器(每个插槽 12 个内核,每个插槽 2 个 NUMA 节点)上,每个 NUMA 节点有 6 个内核。我看到一个系统有 4 个这样的 CPU(所以有 8 个 NUMA 节点,每个有 6 个内核)在自旋锁车队中卡住,直到启用跟踪标志 8048。

    我已经看到这种自旋锁争用会降低只有 4 个 vCPU 的 VM 的性能。跟踪标志 8048 在这些系统上启用时做了它应该做的事情。

    考虑到仍然有一些 4 核频率优化的 CPU,在正确的工作负载下,它们也将从跟踪标志 8048 中受益。

    CMEMTHREAD 等待伴随着跟踪标志 8048 解除的自旋锁争用类型。但请注意:CMEMTHREAD 等待是一个确凿的症状,而不是此特定问题的根本原因。我见过具有高 CMEMTHREAD“等待开始”的系统,其中跟踪标志 8048 和/或 9024 在部署中被延迟,因为累积的 CMEMTHREAD 等待时间相当短。对于自旋锁,累积等待时间通常是错误的。相反,您想查看浪费的 CPU 时间 - 主要由自旋本身表示,其次是由表示潜在不必要的上下文切换的相关等待。


  1. 任务分配给调度程序

    在 NUMA 系统上,假设没有与特定 NUMA 节点关联的连接端点,连接会以循环方式分发到 NUMA 节点(实际上是分配到与其关联的 SQLOS 调度程序组)。如果会话执行并行查询,则强烈倾向于使用来自单个 NUMA 节点的工作线程。嗯...考虑一个 4 NUMA 节点服务器,它的复杂查询分为 4 条路径,默认值为 0 MAXDOP。即使查询仅使用 MAXDOP 工作线程,NUMA 节点上的每个逻辑 CPU 也会有 4 个工作线程。但是在复杂的计划中有 4 条路径——所以 NUMA 节点上的每个逻辑 CPU 上可以有 16 个工作人员——所有这些都用于单个查询!

    这就是为什么有时您会看到一个 NUMA 节点在努力工作而其他节点在闲逛。

    任务分配还有一些其他细微差别。但主要的收获是 CPU 繁忙不一定均匀分布在 NUMA 节点上。(也很高兴意识到 bpool 页面插入(读取或第一页写入)将进入与工作程序所在的调度程序关联的 SQLOS 内存节点中的 bpool。并且被盗页面将优先来自“本地”SQLOS 内存节点也是。

    我发现将 maxdop 从 0 提高到不超过 8 是有帮助的。根据工作负载配置文件(主要是关于并发预期潜在长时间运行查询的数量的 imo),可能需要一直使用 MAXDOP=2。

    调整并行性的成本阈值也可能会有所帮助。我工作的系统往往会消耗高成本的查询,并且很少遇到低于 50 或 100 的计划,因此我通过调整 maxdop(通常在工作负载组级别)比调整成本阈值具有更大的吸引力。


  1. bpool中的相关数据放置

    这是我认为在处理 NUMA 服务器时最直观的条件。通常,它对工作负载性能也不是特别重要。

    如果将表读入 NUMA 节点 3 上的 bpool,然后 NUMA 节点 4 上的查询扫描该表,执行所有跨 NUMA 节点的 bpool 查找,会发生什么情况?

    Linchi Shea 有一篇关于这种性能影响的好文章:

    跨 NUMA 节点访问内存会产生少量额外的内存延迟。我确信有一些工作负载需要消除额外的基本内存延迟以获得最佳性能 - 在我使用的系统上这不是问题。

    但是 - 跨节点访问也带来了另一个可能饱和的传输点。如果活动过多导致 NUMA 节点之间的内存带宽饱和,则节点之间的内存延迟会增加。同样的工作将需要额外的 CPU 周期。

    再次 - 我确信存在内存带宽是一个关键考虑因素的工作负载。但是,对于我的系统,我列出的其他注意事项更为重要。


  1. 物理内存放置

    这个很少见,但当它很重要时,它真的很重要。在大多数服务器上,内存安装几乎自然会在 NUMA 节点之间平衡。但在某些情况下,需要特别注意平衡节点之间的内存。如果内存以不平衡的方式插入,某些系统中的性能可能会被完全破坏。不过,这是一劳永逸的。在几个月的生产服务之后发现这样的问题非常罕见,而不是在第一个真正忙碌的一天之后:-)


大结局!

其他人指出,糟糕的计划选择,可能是由于过时的统计数据,可能会导致您看到的症状。根据我的经验,情况并非如此。糟糕的计划很容易使查询花费比预期更长的时间 - 但通常是因为正在执行的逻辑 IO 比所需的要多。或者由于溢出到 tempdb。在观察服务器时,对 tempdb 的大量溢出应该是显而易见的 - 而不是高 CPU 期望与溢出相关的磁盘写入的可测量等待时间。

相反,如果您观察到的情况与 NUMA 相关,我希望它是上面列举的因素的组合,主要是:

  1. 工作区内存的使用(不会出现在逻辑 IO 计数中)

  2. 由于持久的外部内存条件,这可能是跨 NUMA 节点(如果是这种情况,请寻找相关修复程序)

  3. 并且每次根据授权进行分配时可能会在 NUMA 节点内引起自旋锁争用(使用 T8048 修复)

  4. 并且可能由其他并行查询工作人员过载的逻辑 CPU 上的工作人员执行(根据需要调整 maxdop 和/或并行成本阈值)


Kin*_*hah 8

请使用coreinfo -v(一个 sysinternal 实用程序)输出更新您的问题,以更好地了解您的 CPU/套接字和 NUMA 分布

我们查看了大约 60% 的整体 CPU 利用率。我们没有查看特定于套接字的 CPU 指标。I/O 指标是平均的。

在我看来,你在错误的树上吠叫。SQL ServerNUMA知道。有做跨NUMA内存访问更小的性能损失。您还可以使用此查询来查看NUMA您拥有多少个节点以及分配给哪些 CPU 和内核NUMA

SELECT parent_node_id, scheduler_id, cpu_id
FROM sys.dm_os_schedulers WITH (NOLOCK) 
WHERE [status] = N'VISIBLE ONLINE';
Run Code Online (Sandbox Code Playgroud)

或者只是多少NUMA

select COUNT(distinct Parent_node_id)
from sys.dm_os_schedulers
where [STATUS] = 'VISIBLE ONLINE'
    and Parent_node_ID < 64
Run Code Online (Sandbox Code Playgroud)

我们有一些逻辑读取的查询需要超过 1 分钟。

这通常发生在由于过时的统计数据生成错误的查询计划时。确保您更新了统计信息并且正确地对索引进行了碎片整理

此外,您需要将 MAXDOP 设置为更合理的值避免工作线程饥饿

将您cost threshold of parallelism从默认值 5 设置为一个良好的起始值,例如 45,然后监控该值并根据您的环境进行调整。

如果您正在运行大量即席查询,请打开(设置为 1)optimize for ad hoc workloads以防止计划缓存膨胀。

谨慎使用:如果您在每个 NUMA 节点提供超过 8 个 CPU 的较新机器上运行 SQL Server 2008/2008 R2,则可以使用T8048,如果您使用的是 SQL Server 2012 或 2014,则可以使用修补程序

强烈建议您开始收集有关您的数据库服务器实例的等待统计信息。

请参阅:工作原理:SQL Server(NUMA 本地、外部和离开内存块)