为什么来自不同 SQL Server 实例的这些 T-SQL 作业在同一实例上执行(AlwaysOn 可用性组)

Ran*_*gen 4 sql-server jobs availability-groups sql-server-2017

最近,在我们进行统计更新时,我们的阻止进程仪表板一直在报告被阻止的进程。

很快就找到了原因:更新统计作业步骤 (T-SQL) 在辅助 SQL Server 实例和主 SQL Server 实例上都启动。该作业更新同一数据库的多个统计信息,该数据库是 AlwaysOn 可用性组的一部分。我希望这会在辅助实例上失败。

故障转移历史的简要概述:

由于许可而应保持活动状态的服务器 A(将被命名为活动服务器),在 20/02 晚上 9 点意外故障转移到服务器 B(被动服务器)。

在计划外故障转移之后,我们在 2002 年 2 月 21 日中午 12 点进行了另一次(但这次是计划内的)手动故障转移回 Active Server。

工作经历

在第一次故障转移之前一切都很好,活动服务器是唯一运行该作业的服务器。

在此处输入图片说明 一项工作正在运行。 我们看到在活动端运行的统计更新。(这是当时的主要副本)

在无源服务器作为主要副本的短时间内,我们没有任何监控并且作业历史记录被清除。

故障转移后,回到“正常”状态,在被动节点上处于主节点不到 24 小时后,被动实例上的作业步骤也已在主动实例上启动并运行。

在此处输入图片说明 (我杀死了会话)。

现在对我来说有趣的部分是,这两个作业都在活动服务器上运行,似乎该作业正在使用侦听器访问数据库。但这可能是一个完全不同的原因。

有一个复制作业 PowerShell 任务在每晚凌晨 01 点运行 (dbatools):

powershell.exe Copy-DbaAgentJob -ExcludeJob "CopyJobs,CopyLogins" -Source INDCSPSQLA01  -Destination  INDCSPSQLP01     -Force
Run Code Online (Sandbox Code Playgroud)

我的猜测现在是针对一次,作业复制发生在主动、次要节点 --> 带有 -Force 的主要被动节点。这发生在 21/02 01 AM。

问题

为什么被动实例上的作业步骤在主动实例的数据库上执行?

清单

在这两种情况下,作业目标都是本地的:

在此处输入图片说明

EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
Run Code Online (Sandbox Code Playgroud)

服务器名称正确

select name from sys.servers 
select @@SERVERNAME
Run Code Online (Sandbox Code Playgroud)

两者都返回无源服务器。

主动和被动的作业 ID 不同:

--08C63F07-0853-41DA-BC88-8FDF44AE491F -- passive
--E8C88965-C581-4E06-B651-CC10637FCEEF -- active
Run Code Online (Sandbox Code Playgroud)

两个作业都在其步骤中使用相关数据库:

@database_name=N'DB1', 
Run Code Online (Sandbox Code Playgroud)

--> 不应该在被动实例上访问,导致失败。 没有可读的辅助

在此处输入图片说明

数据库在被动实例上不可访问:

在此处输入图片说明

两台服务器的版本:14.0.3030.27

T-SQL 作业步骤命令示例

 @subsystem=N'TSQL', 
        @command=N'update statistics dbo.table with fullscan ...'
Run Code Online (Sandbox Code Playgroud)

作业开始时,被动实例上没有运行任何内容。

编辑:

重新启动被动节点上的代理“修复”了这个问题,导致执行时出现新错误:

无法连接到 SQL Server“INDCSPSQLP01”。步骤失败。

因此,它不再更新主实例的统计信息

主机名 = 被动和主动服务器,可见运行的作业。 在此处输入图片说明

申请信息

SQLAgent - TSQL JobStep (Job 0x9D358B2EF6C53C4BAD6A61CA87D51BF5 : Step 1)   
SQLAgent - TSQL JobStep (Job 0x6589C8E881C5064EB651CC10637FCEEF : Step 1)   
Run Code Online (Sandbox Code Playgroud)

Ton*_*kle 7

我没有诊断为什么会出现此问题,但是如果您有在可用性组中的数据库上运行的作业,最好在步骤 1 中包含一个检查,该检查使用该fn_hadr_is_primary_replica函数来检查它是在主数据库上运行还是在主数据库上运行次要的。

IF (sys.fn_hadr_is_primary_replica('DB1') <> 1)
  BEGIN
    RAISERROR('%s is secondary', 11, 1, @@servername );
  END
Run Code Online (Sandbox Code Playgroud)

配置此步骤以在失败时退出作业。这比尝试运行失败的东西要好,因为它正在击中辅助。