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

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

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

摘要

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

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

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
    

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

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

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

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

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

    DROP DATABASE <DatabaseName>
    

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

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

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

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

    ALTER DATABASE <DatabaseName> SET hadr OFF
    

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

    消息 35240,级别 16,状态 14,行 1
    数据库 <DatabaseName> 不能加入或取消加入可用性组 <AvailabilityGroupName>。 可用性组的主副本 (replica) 不支持此操作。

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

    ALTER DATABASE <DatabaseName> SET hadr OFF
    

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

    消息 921,级别 16,状态 112,第 1 行
    尚未恢复 DatabaseName<>。 请稍候,然后重试。

解决数据库处于辅助角色时的问题

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

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

若要执行这些操作,请连接到新的主副本 (replica) ,然后运行 ALTER AVAILABILITY GROUP SQL 脚本以删除托管失败可用性数据库的副本 (replica) 。 为此,请按照下列步骤操作。

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

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

  2. 运行以下 SQL 脚本:

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

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

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

当主要副本 (replica) 是可用性组中唯一副本 (replica) 时的解决方法

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

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

DROP AVAILABILITY GROUP <AvailabilityGroupName>

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

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

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

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

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

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

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

    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中,使用 对象资源管理器 连接到托管新可用性组的主副本 (replica) 的 SQL Server 实例。 选择“Always On高可用性”,单击新可用性组,然后选择“可用性组侦听器”。 应找到侦听器。

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

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

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

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

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

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

如果要将可用性组托管在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中,使用 对象资源管理器 连接到托管新可用性组的主副本 (replica) 的 SQL Server 实例。
  9. 选择“Always On高可用性”,单击新可用性组,然后选择“可用性组侦听器”。 应找到侦听器。
  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. 恢复损坏的数据库。 然后将它和辅助副本 (replica) 添加回可用性组。