排查 SQL Server 中处于恢复挂起或可疑状态的 Always On 可用性数据库的问题

本文介绍Microsoft处于 Recovery PendingSuspect 状态的可用性数据库的错误和限制,以及如何将数据库还原到可用性组中的完整功能。

原始产品版本: SQL Server 2012
原始 KB 数: 2857849

总结

假设在 AlwaysOn 可用性组中定义的可用性数据库会转换为 Recovery Pending SQL Server 中的状态 Suspect 。 如果这种情况发生在可用性组的主副本上,数据库可用性将受到影响。 在这种情况下,无法通过客户端应用程序访问数据库。 此外,不能从可用性组中删除或删除数据库。

例如,假设 SQL Server 正在运行,可用性数据库设置为 Recovery PendingSuspect 状态。 使用以下 SQL 脚本查询主要副本的动态管理视图(DMV)时,数据库可能以状态RECOVERY_PENDINGSUSPECT状态报告NOT_HEALTHY,如下所示:

SELECT
    dc.database_name,
    d.synchronization_health_desc,
    d.synchronization_state_desc,
    d.database_state_desc
FROM
    sys.dm_hadr_database_replica_states d
    JOIN sys.availability_databases_cluster dc ON d.group_database_id = dc.group_database_id
    AND d.is_local = 1
database_name          synchronization_health_desc     synchronization_state_desc   database_state_desc
-------------------- ------------------------------ ------------------------------ ---------------------
<DatabaseName>                         NOT_HEALTHY              NOT SYNCHRONIZING      RECOVERY_PENDING
(1 row(s) affected)

脚本用于检查数据库运行状况和同步状态的执行结果的屏幕截图。

此外,此数据库可能报告为 SQL Server Management Studio 中的“未同步/恢复挂起 ”或 “可疑 ”状态。

处于“未同步/恢复挂起”状态的数据库屏幕截图。

在可用性组中定义数据库时,无法删除或还原数据库。 因此,必须采取特定步骤来恢复数据库,并将其返回到生产用途。

详细信息

以下内容讨论了各种情况下处于恢复挂起状态的可用性数据库的错误和限制。

  • 数据库状态阻止还原数据库

    尝试运行以下 SQL 脚本来还原具有 RECOVERY 参数的数据库:

    RESTORE DATABASE <DatabaseName> WITH RECOVERY
    

    运行此脚本时,会收到以下错误消息,因为数据库在可用性组中定义:

    Msg 3104,级别 16,状态 1,第 1 行
    RESTORE 无法对数据库 <DatabaseName> 进行操作,因为它已配置为数据库镜像或已加入可用性组。 如果要还原数据库,请使用 ALTER DATABASE 删除镜像或从其可用性组中删除数据库。

    消息 3013,级别 16,状态 1,行 1
    RESTORE DATABASE 正在异常终止。

  • 数据库状态阻止删除数据库

    尝试运行以下 SQL 脚本来删除数据库:

    DROP DATABASE <DatabaseName>
    

    运行此脚本时,会收到以下错误消息,因为数据库在可用性组中定义:

    Msg 3752,级别 16,状态 1,第 1 行
    数据库 <DatabaseName> 当前已加入可用性组。 在删除数据库之前,需要将其从可用性组中删除。

  • 数据库状态可防止从可用性组中删除数据库

    尝试运行以下 SQL 脚本以从可用性组中删除数据库:

    ALTER DATABASE <DatabaseName> SET hadr OFF
    

    尝试运行此脚本时,会收到以下错误消息,因为可用性数据库属于主副本:

    Msg 35240,级别 16,状态 14,第 1 行
    <数据库 DatabaseName> 无法加入可用性组 <AvailabilityGroupName> 或从其取消加入。 可用性组的主要副本不支持此操作。

    由于出现此错误消息,可能不得不对数据库进行故障转移。 故障转移数据库后,拥有恢复挂起数据库的副本位于辅助角色中。 在这种情况下,尝试再次执行以下 SQL 脚本,以从辅助副本的可用性组中删除数据库:

    ALTER DATABASE <DatabaseName> SET hadr OFF
    

    但是,你仍无法从可用性组中删除数据库,并且收到以下错误消息,因为数据库仍处于恢复挂起状态:

    Msg 921,级别 16,状态 112,第 1 行
    数据库 <数据库名称> 尚未恢复。 请等待,然后重试。

当数据库处于辅助角色时的解决方案

若要解决此问题,请执行以下常规操作:

  • 从可用性组中删除在数据库处于辅助角色时承载损坏数据库的副本。
  • 解决影响系统并可能导致数据库故障的任何问题。
  • 将副本还原到可用性组。

若要执行这些操作,请连接到新的主副本,然后运行 ALTER AVAILABILITY GROUP SQL 脚本以删除承载失败可用性数据库的副本。 要设置部门,请按照以下步骤操作。

这些步骤假定主副本首先托管损坏的数据库。 因此,必须首先发生故障转移,才能将托管损坏的数据库的副本转换为辅助角色。

  1. 连接到运行 SQL Server 且托管辅助副本的服务器。

  2. 运行以下 SQL 脚本:

    ALTER AVAILABILITY GROUP <AvailabilityGroupName> FAILOVER
    
  3. 运行以下 SQL 脚本,从可用性组中删除托管损坏数据库的副本:

    ALTER AVAILABILITY GROUP <AvailabilityGroupName> REMOVE REPLICA ON '<SQLServerNodeName>'
    
  4. 解决运行 SQL Server 且可能导致数据库故障的服务器上的任何问题。

  5. 将副本添加回可用性组。

当主副本是可用性组中的唯一副本时的解决方案

如果主副本托管损坏的数据库,并且是可用性组中唯一的工作副本,则必须删除可用性组。 删除可用性组后,可以从备份恢复数据库,也可以应用其他紧急恢复工作来还原数据库并恢复生产。

若要删除可用性组,请使用以下 SQL 脚本:

DROP AVAILABILITY GROUP <AvailabilityGroupName>

此时,可以尝试恢复有问题的数据库。 或者,可以从上次已知的良好备份副本还原数据库。

删除可用性组时的解决方法

删除可用性组时,侦听器资源也会被删除,并中断与可用性数据库的应用程序连接。

若要最大程度地减少应用程序停机时间,请使用以下方法之一通过侦听器维持应用程序连接,并删除可用性组:

方法 1:将侦听器与故障转移群集管理器中的新可用性组(角色)相关联

此方法允许你在删除并重新创建可用性组时维护侦听器。

  1. 在现有可用性组侦听器将连接定向到的 SQL Server 实例上,创建新的空可用性组。 若要简化此过程,请使用 Transact-SQL 命令创建没有辅助副本或数据库的可用性组:

    USE master
    GO
    CREATE AVAILABILITY GROUP ag FOR REPLICA ON 'sqlnode1' WITH (
        ENDPOINT_URL = 'tcp://sqlnode1:5022',
        AVAILABILITY_MODE = ASYNCHRONOUS_COMMIT,
        FAILOVER_MODE = MANUAL
    )
    
  2. 启动故障转移群集管理器,然后选择 左侧窗格中的角色 。 在列出角色的窗格中,选择原始可用性组。

  3. 在“资源”选项卡下的底部窗格中,右键单击可用性组资源,然后选择“属性”。 选择“ 依赖项 ”选项卡,删除侦听器的依赖项,然后选择“ 确定”。

    可用性组属性“依赖项”选项卡的屏幕截图。

  4. 在资源下,右键单击侦听器,选择“ 更多操作”,然后选择“ 分配到其他角色”。

  5. “分配源到角色 ”对话框中,选择新的可用性组,然后选择“ 确定”。

    “将源分配到角色”对话框的屏幕截图,其中显示了添加新的可用性组。

  6. “角色 ”窗格中,选择新的可用性组。 在底部中间窗格中的“资源”选项卡下,现在应会看到新的可用性组和侦听器资源。 右键单击新的可用性组资源,然后选择“ 属性”。

  7. 单击“依赖项”选项卡,从下拉列表框中选择侦听器资源,然后选择“确定”。

    “新建可用性组属性依赖项”选项卡的屏幕截图。

  8. 在 SQL Server Management Studio 中,使用对象资源管理器连接到承载新可用性组主副本的 SQL Server 实例。 选择 AlwaysOn 高可用性,单击新的可用性组,然后选择 可用性组侦听器。 应找到侦听器。

  9. 右键单击侦听器,选择“属性,键入侦听器的相应端口号,然后选择“确定”。

    可用性组侦听器属性的屏幕截图,其中显示了侦听器的配置。

这可确保使用侦听器的应用程序仍可使用它连接到托管生产数据库的 SQL Server 实例,而不会中断。 现在可以完全删除原始可用性组并重新创建。 也可以将数据库和副本添加到新的可用性组。

如果重新创建原始可用性组,则应将侦听器重新分配到可用性组角色,设置新可用性组资源和侦听器之间的依赖关系,然后将端口重新分配给侦听器。 为此,请按照下列步骤进行操作:

  1. 启动故障转移群集管理器,然后选择 左侧窗格中的角色 。 在列出角色的窗格中,单击托管侦听器的新可用性组。
  2. 在“资源”选项卡下的底部中间窗格中,右键单击侦听器,选择“更多操作”,然后选择“分配到其他角色”。 在对话框中,选择重新创建的可用性组,然后选择“ 确定”。
  3. “角色 ”窗格中,单击重新创建的可用性组。 在底部中间窗格中的“资源”选项卡下,现在应会看到重新创建的可用性组和侦听器资源。 右键单击重新创建的可用性组资源,然后选择“ 属性”。
  4. 选择“ 依赖项 ”选项卡,从下拉列表框中选择侦听器资源,然后选择“ 确定”。
  5. 在 SQL Server Management Studio 中,使用对象资源管理器连接到承载重新创建可用性组的主要副本的 SQL Server 实例。 选择 AlwaysOn 高可用性,单击新的可用性组,然后选择 可用性组侦听器。 应找到侦听器。
  6. 右键单击侦听器,选择“属性,键入侦听器的相应端口号,然后选择“确定”。

方法 2:将侦听器与现有的 SQL Server 故障转移群集实例(SQLFCI) 相关联

如果要在 SQL Server 故障转移群集实例(SQLFCI)上托管可用性组,则可以在删除后重新创建可用性组时,将侦听器群集资源与 SQLFCI 群集资源组相关联。

  1. 启动故障转移群集管理器,然后选择 左侧窗格中的角色

  2. 在列出角色的窗格中,选择原始可用性组。

  3. 在“资源”选项卡下的底部中间窗格中,右键单击可用性组资源,然后选择“属性”。

  4. 选择“ 依赖项 ”选项卡,删除侦听器的依赖项,然后选择“ 确定”。

  5. 在“资源”选项卡下的底部中间窗格中,右键单击侦听器,选择“更多操作”,然后选择“分配到其他角色”。

  6. “将资源分配到角色 ”对话框中,单击 SQL Server FCI 实例,然后选择“ 确定”。

    “将资源分配到角色”对话框的屏幕截图。

  7. “角色 ”窗格中,选择 SQLFCI 组。 在底部中间窗格中的“资源”选项卡下,现在应会看到新的侦听器资源。

这可确保使用侦听器的应用程序仍可使用它连接到托管生产数据库的 SQL Server 实例,而不会中断。 现在可以删除原始可用性组并重新创建。 也可以将数据库和副本添加到新的可用性组。

重新创建可用性组后,将侦听器重新分配给可用性组角色。 然后设置新可用性组资源与侦听器之间的依赖关系,并将端口重新分配给侦听器:

  1. 启动故障转移群集管理器,然后选择 左侧窗格中的角色
  2. 在列出角色的窗格中,单击原始 SQLFCI 角色。
  3. 在底部中间窗格中的“资源”选项卡下,右键单击侦听器,选择“更多操作”,然后选择“分配到其他角色”。
  4. 在对话框中,单击重新创建的可用性组,然后选择“ 确定”。
  5. “角色 ”窗格中,选择新的可用性组。
  6. “资源 ”选项卡下,应会看到新的可用性组和侦听器资源。 右键单击新的可用性组资源,然后选择“ 属性”。
  7. 选择“ 依赖项 ”选项卡,从下拉列表框中选择侦听器资源,然后选择“ 确定”。
  8. 在 SQL Server Management Studio 中,使用对象资源管理器连接到承载新可用性组主副本的 SQL Server 实例。
  9. 选择 AlwaysOn 高可用性,单击新的可用性组,然后选择 可用性组侦听器。 应找到侦听器。
  10. 右键单击侦听器,选择“属性,键入侦听器的相应端口号,然后选择“确定”。

方法 3:删除可用性组,然后使用相同的侦听器名称重新创建可用性组和侦听器

此方法将导致当前连接的应用程序发生小中断,因为删除可用性组和侦听器,然后重新创建:

  1. 删除可用性组。

    注意

    这也会删除侦听器。

  2. 立即在托管生产数据库的同一服务器上创建一个新的空可用性组,其中包含侦听器定义。

    例如,假设可用性组侦听器为 aglisten。 以下 Transact-SQL 语句创建一个没有主数据库或辅助数据库的可用性组,但它还会创建名为 aglisten 的侦听器。 应用程序可以使用此侦听器进行连接。

    USE master
    GO
        CREATE AVAILABILITY GROUP ag FOR REPLICA ON 'sqlnode1' WITH (
            ENDPOINT_URL = 'tcp://sqlnode1:5022',
            AVAILABILITY_MODE = ASYNCHRONOUS_COMMIT,
            FAILOVER_MODE = MANUAL
        ) LISTENER 'aglisten' (
            WITH IP ((N'11.0.0.25', N'255.0.0.0')),
            PORT = 1433
        )
    GO
    
  3. 恢复损坏的数据库。 然后将它和辅助副本添加回可用性组。