HADR_SYNC_COMMIT 在 SQL Server 上等待

Dat*_*ill 4 sql-server high-availability availability-groups

让我在这篇文章的序言中说,我在跟踪中遗漏了一些事件,但我已经添加了它们,以便下次发生这种情况时添加它们。

最近,我们在我们的环境中看到了 HADR_SYNC_COMMIT 等待类型的奇怪激增(~40k tran/s)。今天的“事件”发生在凌晨4点58分:

在此输入图像描述

在此输入图像描述

在继续之前,我必须补充一点,我们正在对一个大型审计表进行在线索引维护(从 OLTP 表触发器大量记录到此审计表的意义上进行审计),并且索引重建本身被阻止约 22 秒。显然,这在这个特定实例中发挥了作用,但我不太确定它与 HADR_SYNC_COMMIT 有何关系。此外,我们在白天不进行索引维护时也看到过这种情况发生。

查看跟踪,这是我在主设备上看到的: 在此输入图像描述

在此输入图像描述

在此输入图像描述

...以及辅助设备上的所有内容: 在此输入图像描述

...最后回到主要: 在此输入图像描述

2023 年 12 月 1 日凌晨 4:11 左右再次发生了类似的问题,我相信我明白发生了什么。不幸的是,我没有针对这种情况的扩展事件,但我确实有一些日志记录可以描绘出更清晰的画面。从 2023-12-01 04:10:18.5430090 开始,Ola 的索引维护记录了相关数据库上索引的开始时间。Ola 报告的完成时间为 2023-12-01 04:11:13.9431563,但我相信实际 REBUILD WITH ONLINE = ON 完成的时间要早​​得多。

在查看 DPA 时,我注意到 pagelatch_sh 和 pagelatch_ex 等待时间在凌晨 4:11:03-4:11:04 出现峰值:

在此输入图像描述

紧接着这些等待,同一个查询开始看到 HADR_SYNC_COMMIT,并且这些相同的等待在凌晨 4:11:13-4:11:14 完全消失,这正是 Ola 报告索引完成的时间。我的假设是索引 REBUILD 是在凌晨 4:11:03 提交的(大约需要 45 秒的工作),这导致同一数据库中的不相关 INSERT 查询只是等待所有这些日志块在辅助数据库上硬化。一旦索引完成,剩余的日志块就会立即硬化,因为它们只是微小的插入。

Sea*_*ser 5

我想说的是,我对使用 XE 进行深入研究表示赞赏,这绝对是最终解决方案中的正确步骤。话虽如此,我们不太可能以任何有意义的方式直接提供帮助。让我解释。

HAD_SYNC_COMMIT 等待几乎与任何其他等待一样,因为它们是一种等待类型,但它们实际上每约 3 秒重置一次(实现细节),这就是hadr_db_commit_mgr_harden_still_waiting出现的原因,它将根据需要进行多轮检查,直到日志块被删除。标记为硬化。除了实现细节之外,其他所有事情都像其他等待一样,并且会发生相同的问题 - 请记住 SQL Server 使用协作调度,如果您了解细节是事件驱动的,例如许多事件被发出信号(例如等待完成)并且任务可以前进)可能会导致突发护航类型问题(所有线程都在等待,然后所有线程都被“唤醒”,这会导致 cpu/调度竞争,然后再次导致护航)。

不幸的是,在调查这些类型的等待时,您将需要大量数据,包括本地和远程主机的数据包捕获、HADR 的 XE、文件/磁盘、调度以及 Windows 中磁盘、过滤器、CPU 的 ETW 跟踪。这是大量数据,我不建议您在这里这样做,因为问题出在您提供的信息中。

 I must add that we were doing ONLINE index maintenance on a large audit table [...]
Run Code Online (Sandbox Code Playgroud)

任何大型且长期的事务(尤其是与索引相关的活动)都不太适合可用性组的实施方式。离线索引重建作为单个庞然大物的事务完成,在线索引重建更好,因为它们在各个点上都是较小的事务,但这两种操作都可以真正驱动 CPU 和 IO - 这不一定是坏事如果您的服务器具有在短时间内生成大量日志的性能能力,并且生成速度快于网络延迟+磁盘延迟,则数据库(和实例)将无法跟上未完成的日志生成发送到其他副本。您将开始在同步副本上遇到同步提交等待(因为它仅适用于同步提交伙伴)。

可用性组通过日志块发送数据,日志块是日志级别项目的最小逻辑分组单位,最小大小为 512 字节(曾经是 1 个扇区大小,此后已更改为 4k、8k、16k 甚至32k 扇区大小),最大为 60k,但它们的实际大小取决于提交是结束块还是块达到最大大小。这样做的要点是,事务本身不是传输单位,来自多个不同会话的多个事务可以并且将会在整个日志块中混合在一起。因此,如果您生成大量日志块并且事务在这些日志块中交织在一起,则任何事务提交都需要在继续之前硬化其自己事务的未完成日志块,这可能是另一个日志块的一部分随着情况开始好转,未来也会走得更远。

另一个争论点是网络,这也是 SQL Server 中 UCS 的一个实现细节。在 SQL Server 2022+ 中的分布式 AG(目前存在一些问题)之外,使用单个连接通过 TCP 将数据流式传输到每个副本。这意味着,即使使用大带宽网络,您也会受到延迟的限制,因为这将决定未完成请求的粗略数量,这些请求可能会也可能不会达到 SQL Server 中的限制(该限制已于 2022 年提高)。这意味着您永远无法使用可用性组使用单个 SQL Server 实例来真正填满大型带宽管道,而且延迟更为重要 - 因此,在半个地球上同步提交副本的延迟为 150 毫秒严重的备份和大量的日志生成工作负载 - 即索引重建。

我提到了调度和cpu数据的需要,这是因为日志生成发生了,但是需要打包并通过网络发送。这一切都是在各种线程和队列中异步发生的。如果实例在单个 cpu 上有 cpu 压力,这可能会影响打包(压缩、加密、序列化、UCS 信息 [boxcars]、消息信息)和发送(发送线程、接收线程)以及正在执行以下操作的辅助副本相同的事情以相反的顺序。对于可读辅助副本尤其如此,其中读取工作负载可能会阻碍或降低 AG 及时强化的能力。请注意,强化需要写入磁盘(这是 IO 数据的来源),并且不需要重做。

这就是说,在重建索引时,这是预料之中的,我不会浪费时间进一步研究它。