疑难解答链接 - Azure SQL 托管实例

适用于:Azure SQL 托管实例

本文介绍如何监视和排查 SQL Server 与 Azure SQL 托管实例之间链接的问题。

可以使用 Transact-SQL (T-SQL)、Azure PowerShell 或 Azure CLI 检查链接的状态。 如果遇到问题,可以使用错误代码来排查问题。

通过检查两个实例之间的网络并验证对于链接环境已正确准备好,可以解决创建链接的许多问题。

初始播种

在 SQL Server 和 Azure SQL 托管实例之间建立链接时,数据复制开始前会出现初始种子设定阶段。 初始种子设定阶段是操作过程中耗时最长且开销最大的阶段。 初始种子设定完成后,数据将会同步,但只会复制后续的数据更改。 初始种子设定完成所需的时间取决于数据大小、主数据库上的工作负荷强度以及主要副本和次要副本网络之间的链接速度。

如果两个实例之间的链接速度比所需速度慢,则种子设定时间可能会受到明显影响。 可以使用有说明的种子设定速度、总数据大小以及链接速度来估计初始种子设定阶段在数据复制开始前需要多长时间。 例如,对于单个 100 GB 的数据库,如果链接每小时能够推送 84 GB 数据,并且没有其他数据库正在进行向不同链接的种子设定,则初始种子设定阶段需要花费大约 1.2 小时。 如果链路每小时只能传输 10 GB,那么分发 100 GB 的数据库大约需要 10 小时。 如果有多个数据库可以通过多个链接进行复制,则会并行执行种子设定,并且当与慢速链接速度相结合时,初始种子设定阶段可能需要相当长的时间,尤其是当来自所有数据库的并行种子设定超过可用链接带宽时。

初始种子设定阶段对网络中断以及实例维护或故障转移操作没有弹性。 如果 SQL Server 和 SQL 托管实例之间的双向连接暂时丢失,或者在初始播种过程中重启或故障转移 SQL Server 或 SQL 托管实例,则播种过程将重新开始。

重要

初始分发阶段可能会因为极低的速度或繁忙的链接而持续数天。 在这种情况下,创建链接可能会超时。创建链接会在 6 天后自动取消。

如果链接出现问题,可以使用 SQL Server Management Studio(SSMS)、Transact-SQL(T-SQL)、Azure PowerShell 或 Azure CLI 获取有关链接的当前状态的信息。

使用 T-SQL 获取链接状态的快速状态详细信息,然后使用 Azure PowerShell 或 Azure CLI 获取有关链接当前状态的完整信息。

从 SQL Server Management Studio(SSMS)21.0(预览版)开始,可以使用链接监视。

若要检查 SSMS 中的链接状态,请执行以下步骤:

  1. 连接到托管链接的副本。

  2. 在“对象资源管理器”中,展开“Always On 高可用性”,并展开“可用性组”。

  3. 右键单击链接的名称,然后选择“ 属性 ”以打开 “链接属性 ”窗口:

    SSMS 中链接的右键单击菜单的屏幕截图,其中突出显示了属性。

  4. 链接属性 ”窗口显示有关链接的有用信息,例如副本信息、链接状态和终结点证书过期日期:

    SSMS 中链接属性窗口的屏幕截图。

replicaState 值描述当前链接。 如果状态还包括“错误”,则在状态中列出的操作期间发生了错误。 例如,LinkCreationError 指示创建链接时出错。

一些可能的 replicaState 值包括:

  • CreatingLink:初始种子设定
  • LinkSynchronizing:数据复制正在进行中
  • LinkFailoverInProgress:正在进行故障转移

有关链接状态属性的完整列表,请查看分布式可用性组 - GET REST API 命令。

计划的故障转移超时

如果次要副本无法跟上主副本的更改并滞后,计划的故障转移可能会超时并失败并出现错误。

若要解决此问题,请执行以下步骤:

  1. 检查两个实例之间的复制滞后时间。
  2. 如果复制滞后时间较高,请等待辅助副本赶上主副本。 如果滞后时间仍然存在(例如暂停主副本上的工作负荷、改善两个实例之间的链接网络吞吐量或增加辅助副本上的资源容量),则可能需要执行其他故障排除步骤。
    • 停止SQL Server主副本上的工作负荷的最简单方法是切断与实例的应用程序连接。
  3. 辅助副本赶上主副本后,再次尝试计划的故障转移。

初始化链接时,可能会出现以下错误(链接状态:LinkInitError):

创建链接时可能会发生以下错误(链接状态: LinkCreationError

  • 错误 41977:目标数据库未响应。 检查链接参数,然后重试。
  • 日志过早截断:如果在初始种子设定完成之前截断事务日志,则可能会看到以下错误之一:
    • 错误 1408:复制到远程数据库的失败,由于主副本和辅助副本之间缺少日志文件重叠,无法恢复。 删除现有链接并创建新链接以重启复制。
    • 错误 1412:复制到远程数据库的失败,由于与主副本的日志文件大小不匹配,无法恢复。 删除现有链接并创建新链接以重启复制。

错误 1412

首次创建 链接时,进程的第一部分将数据库的完整备份从主副本播种到次要副本。 完成完整备份的初始设置后,连接开始通过将主副本中的差异数据应用到辅副本来复制数据。 此过程会无限期地继续,直到发出故障转移命令或删除链接。

如果在完整备份的初始填充期间主要副本上进行事务日志备份,事务日志会截断。 链接创建失败,出现错误 1412,因为初始种子设定所需的事务日志中的数据不再可用。 如果在 Azure SQL 托管实例 中的 SQL Server 错误日志中看到错误 1412,则必须删除并重新创建链接。

若要抢先避免此问题,请在初始种子设定阶段暂停事务日志备份。

如果在初始种子设定阶段(尤其是对于非常大的数据库)期间需要事务日志备份,可以选择 手动防止日志截断 ,或使用 T-SQL 脚本自动执行进程,以便在关键阶段自动暂停日志备份,以及何时安全。

手动防止日志截断

本部分中的步骤演示如何针对虚拟表启动事务,以防止初始播种阶段的日志截断。 此过程需要手动监视数据填充进度,并仔细把握时机,以确保在数据填充完成之前不会发生日志截断。

  1. 监视播种进度。 可以使用以下 T-SQL 查询来监视初始同步的进度:

    SELECT * FROM sys.dm_exec_requests WHERE database_id = @dbId AND command = 'VDI_CLIENT_WORKER'
    
  2. 在播种接近 90% 完成时,在虚设表上发出 BEGIN TRAN 命令但不提交,以保持事务打开并防止日志截断。

  3. 仔细监视事务日志磁盘空间,以确保在事务打开时不会超过存储容量。

  4. 当做种达到 100%时,使用 COMMIT TRAN完成交易。

例如,在初始种子设定达到 90%之前,请运行以下命令以创建虚拟表以避免错误 1412:

-- Create table
CREATE TABLE Prevent1412
(
    Id        INT,
    CreatedAt DATETIME
);

然后,在种子设定即将完成时,运行以下命令以防止日志截断:

BEGIN TRAN;

INSERT INTO Prevent1412 (Id, CreatedAt)
VALUES (1, GETDATE());

注意

事务开始后,事务日志不再截断,因此请仔细监视事务日志磁盘空间,以确保它在事务打开时不会超过存储容量。

完成数据初始化后,可以提交事务来截短日志:

COMMIT TRAN;

迁移完成后,可以删除虚拟表:

DROP TABLE Prevent1412;

自动暂停日志备份

或者,当使用 T-SQL 脚本安全时,可以自动执行在关键阶段自动暂停日志备份的过程。

在迁移开始之前,可以执行以下脚本:

-- Get last backup date
SELECT TOP 1 @lastBackupTime = b.backup_finish_date
FROM master.sys.sysdatabases d 
LEFT OUTER JOIN msdb..backupSET b
ON b.database_name = d.name
AND b.type = 'L'
WHERE d.name = @dbName
ORDER BY backup_finish_date DESC
SELECT @diffInMins = DATEDIFF(minute, @lastBackupTime, CURRENT_TIMESTAMP);

-- Get database id and group database id
SELECT @agDbId = group_database_id, @dbId = database_id FROM sys.databases WHERE name = @dbName

-- If there is no group database id, no need for checks
IF (@agDbId IS NOT NULL)
BEGIN
              -- Get last seeding start time and check if backup (VDI client) is actually running
              SELECT TOP 1 @seedingStartTime = start_time, @state = current_state, @agDbId = ag_db_id FROM sys.dm_hadr_automatic_seeding ORDER BY start_time DESC

              IF (@state = 'PENDING' OR @state = 'CHECK_IF_SEEDING_NEEDED' OR @state = 'LIMIT_CONCURRENT_BACKUPS')
                             SET @seedingStarting = 1
              ELSE
                             SET @seedingStarting = 0
              
              SELECT @backupWorkers = COUNT(*) FROM sys.dm_exec_requests WHERE database_id = @dbId AND command = 'VDI_CLIENT_WORKER'

              -- Check if seeding is done by looking at remote replica state and health
              SELECT TOP 1 @db_state = synchronization_state_desc, @db_health = synchronization_health_desc FROM sys.dm_hadr_database_replica_states WHERE database_id = @dbId AND is_local = 0

              IF (@db_state = N'SYNCHRONIZING' AND @db_health = N'HEALTHY')
              SET @seedingDone = 1
              ELSE
              SET @seedingDone = 0
END

-- If X minutes has passed since last log backup, do it, we don't want to wait anymore
IF (@alreadyFailed = 1 or @diffInMins > {set_minutes})
BEGIN
              {do_log_backup}
              SET @alreadyFailed = 1
              CONTINUE;
END

-- If seeding has started and finished take log backups
IF ((@agDbId IS NOT NULL) AND (@seedingStartTime IS NOT NULL) AND (@startTime < @seedingStartTime) AND (@seedingDone = 1))
BEGIN
              {do_log_backup}
              SET @alreadyFailed = 1
              CONTINUE;
END

-- If database is not in ag or
-- If seeding has not started or
-- If seeding is ongoing 
-- Take log backups
IF ((@agDbId IS NULL) OR (@seedingStartTime IS NULL) OR (@startTime > @seedingStartTime) OR (@seedingStarting = 1) or (@backupWorkers > 0))
BEGIN
              {do_log_backup}
              CONTINUE;
END

强制故障转移后的状态不一致

在强制故障转移后,你可能会遇到脑裂情况,即两个副本都担当主要角色,这导致链接处于不一致状态。 如果在灾难期间故障转移到次要副本,然后主副本重新联机,则可能会发生这种情况。

首先,确认你处于脑裂情况中。 可以使用 SQL Server Management Studio (SSMS) 或 Transact-SQL (T-SQL) 来执行此操作。

在 SSMS 中连接到 SQL Server 和 SQL 托管实例,然后在“对象资源管理器”中,展开“Always On 高可用性”中的“可用性组”节点下的“可用性副本”。 如果两个不同的副本被列为“(主要)”,则表示处于裂脑情况中。

或者,可以在 SQL Server 和 SQL 托管实例上运行以下 T-SQL 脚本来检查副本的角色:

-- Execute on SQL Server and SQL Managed Instance 
USE master
DECLARE @link_name varchar(max) = '<DAGName>'
SELECT
   ag.name [Link name], 
   rs.role_desc [Link role] 
FROM
   sys.availability_groups ag 
   JOIN sys.dm_hadr_availability_replica_states rs 
   ON ag.group_id = rs.group_id 
WHERE 
   rs.is_local = 1 AND ag.is_distributed = 1 AND ag.name = @link_name 
GO

如果这两个实例在“链接角色”列中都作为“主要”实例列出,则表明处于裂脑情况。

要解决裂脑状态,请首先对曾是原始主要实例的任意副本进行备份。 如果原始主数据库是 SQL Server,则执行尾日志备份。 如果原始主实例是 SQL 托管实例,则进行仅复制完整备份。 在备份完成后,在分布式可用性组中,将曾经是原始主要副本但现在将成为新的辅助副本的副本设置为辅助角色。

例如,在真正发生灾难时,假设你已强制将 SQL Server 工作负载故障转移到 Azure SQL 托管实例,并且你打算继续在 SQL 托管实例上运行工作负载,请在 SQL Server 上进行尾日志备份,然后将分布式可用性组设置为 SQL Server 上的辅助角色,如下例所示:

--Execute on SQL Server 
USE master
ALTER AVAILABILITY GROUP [<DAGName>] 
SET (ROLE = SECONDARY) 
GO 

接下来,使用链接执行从 SQL 托管实例到 SQL Server 的计划内手动故障转移,如下例所示:

--Execute on SQL Managed Instance 
USE master
ALTER AVAILABILITY GROUP [<DAGName>] FAILOVER 
GO 

证书已过期

用于链接的证书可能会过期。 如果证书过期,则链接会失败。 若要解决此问题, 请轮换证书

迁移到 SQL 托管实例后的已知问题

迁移到 Azure SQL 托管实例后,请考虑以下已知问题:

迁移到 SQL 托管实例后还原操作失败

如果您将启用了 加速数据库恢复 的 SQL Server 2019 及更高版本的数据库迁移到 Azure SQL 托管实例,但将永久性版本存储(PVS)配置为文件组以外的 PRIMARY,则可能会在目标 SQL 托管实例上遇到还原操作失败的情况。

若要解决此问题,请确保在将 永久性版本存储(PVS)设置为源 SQL Server 数据库上的 PRIMARY,然后再将其迁移到 SQL 托管实例。 如果您已经在没有将 PVS 设置为 PRIMARY 的情况下迁移了数据库,可以在源 SQL Server 数据库上设置 PVS,然后重新迁移数据库到 SQL 托管实例。

迁移到 SQL 托管实例后无法使用加速数据库恢复

从 SQL Server 2019 开始,如果将数据库迁移到 Azure SQL 托管实例,并且源数据库已禁用 加速数据库恢复 ,则无法在目标 SQL 托管实例上使用加速数据库恢复。

若要解决此问题,请确保在将数据库迁移到 SQL 托管实例之前,在源 SQL Server 数据库上 启用加速数据库恢复 。 如果已在未启用加速数据库恢复的情况下迁移数据库,则可以在源 SQL Server 数据库上启用该数据库,然后将数据库重新迁移到 SQL 托管实例。

SQL Server 2017 和早期版本不支持加速数据库恢复,因此此问题不适用于从这些版本的 SQL Server 迁移的数据库。

迁移到 SQL 托管实例后无法使用 Service Broker

如果将数据库迁移到 Azure SQL 托管实例,并且 源数据库上禁用 Service Broker,则无法在目标 SQL 托管实例上使用 Service Broker。

若要解决此问题,请确保先在源 SQL Server 数据库上启用 Service Broker,然后再将其迁移到 SQL 托管实例。 如果已在未启用 Service Broker 的情况下迁移数据库,则可以在源 SQL Server 数据库上启用该数据库,然后将数据库重新迁移到 SQL 托管实例。

测试网络连接

SQL Server 和 SQL 托管实例之间必须有双向网络连接,链接才能正常工作。 在 SQL Server 端打开端口并在 SQL 托管实例端配置 NSG 规则后,使用 SQL Server Management Studio (SSMS) 或 Transact-SQL 测试连接。

通过在 SQL Server 和 SQL 托管实例上创建临时 SQL 代理作业来测试网络,以检查两个实例之间的连接。 在 SSMS 中使用网络检查器时,系统会自动为你创建作业,并在测试完成后将其删除。 如果使用 T-SQL 测试网络,则需要手动删除 SQL 代理作业。

注意

目前不支持通过 Linux 上 SQL Server 上的 SQL Server 代理执行 PowerShell 脚本,因此目前无法从 Linux 上 SQL Server 上的 SQL Server 代理作业执行 Test-NetConnection

若要使用 SQL 代理测试网络连接,需要满足下面的要求:

  • 执行测试的用户必须具有为 SQL Server 和 SQL 托管实例创建作业的权限(作为 sysadmin 或属于 msdb 的 SQLAgentOperator 角色)。
  • SQL Server 代理服务必须在 SQL Server 上运行。 由于代理在 SQL 托管实例上默认处于启用状态,因此无需采取其他操作。

请考虑以下事项:

  • 为了避免误报,网络路径上的所有防火墙都必须允许 Internet 控制消息协议(ICMP)流量。
  • 为了避免误报,网络路径上的所有防火墙都必须允许专有 SQL Server UCS 协议上的流量。 阻止协议可能会导致连接测试成功,但无法创建链接。
  • 需要正确配置具有数据包级防护措施的高级防火墙设置,以正确允许 SQL Server 和 SQL 托管实例之间的流量。

若要在 SSMS 中测试 SQL Server 与 SQL 托管实例之间的网络连接,请执行以下步骤:

  1. 连接到将在 SSMS 中作为主要副本的实例。

  2. 在“对象资源管理器”中,展开数据库,然后右键单击要链接到次要副本的数据库。 选择“任务”>“Azure SQL 托管实例链接”>“测试连接”,以打开“网络检查器”向导:

    SSMS 中对象浏览器的屏幕截图,在数据库链接中右键单击菜单中选择“测试连接”。

  3. 在“网络检查器”向导的“简介”页上,选择“下一步”

  4. 如果满足“先决条件”页上的所有要求,请选择“下一步”。 否则,请解决任何未满足的先决条件,然后选择“重新运行验证”

  5. 在“登录”页上,选择“登录”以连接到将作为次要副本的其他实例。 选择下一步

  6. 检查“指定网络选项”页上的详细信息,并在必要时提供 IP 地址。 选择下一步

  7. 在“摘要”页上,查看向导执行的操作,然后选择“完成”以测试两个副本之间的连接。

  8. 查看“结果”页,验证两个副本之间是否存在连接,然后选择“关闭”以完成。

注意

仅当源环境和目标环境之间有已经过验证的网络连接时,才继续执行后续步骤。 否则,请先排查网络连接问题,然后再继续。

有关链接功能的详细信息,请参阅以下资源: