疑难解答:查找 SQL Server 事务复制错误

适用于:SQL ServerAzure SQL 托管实例

如果对事务复制的工作机制没有基本的了解,那么排查复制错误可能会遭遇挫败。 创建发布的第一步是使用快照代理创建快照并将其保存到快照文件夹。 接下来,分发代理将该快照应用于订阅服务器。

此过程可创建发布并将其设为同步状态。 同步分三个阶段进行:

  1. 事务发生在复制对象上,并在事务日志中将其标记为“用于复制”。

  2. 日志读取器代理扫描事务日志并查找标记为“用于复制”的事务。然后这些事务被保存为分发数据库。

  3. 分发代理使用读取器线程扫描分发数据库。 然后,通过使用编写器线程,此代理连接到订阅服务器,将这些更改应用于订阅服务器。

此过程的任何一步都可能发生错误。 查找这些错误可能是故障排除同步问题最具挑战性的方面。 还好可使用复制监视器简化此过程。

注意

本疑难解答指南旨在介绍故障排除方法。 本指南无法解决具体错误,但可提供查找复制错误的通用指南。 其中提供了一些具体示例,但实际解决方法因环境而异。 示例错误基于教程:配置两个完全连接的服务器之间的复制(事务型)教程。

故障排除方法

应考虑的问题

  1. 同步过程中,复制失败出现在何处?
  2. 哪个代理遇到错误?
  3. 上次复制成功是在什么时候? 从那以后有什么变化?

要执行的步骤:

  1. 使用复制监视器确定在哪个时候遇到错误(哪个代理?):

    • 如果在“发布服务器到分发服务器”部分发生错误,则是日志读取器代理出现问题
    • 如果在“分发服务器到订阅服务器”部分发生错误,则是分发代理出现问题
  2. 在作业活动监视器中查看该代理的作业历史记录,确定错误的详细信息。 如果作业历史记录未显示足够的详细信息,则可以在该特定代理上 启用详细日志记录

  3. 尝试确定错误的解决方案。

查找快照代理错误

快照代理生成快照并将其写入指定的快照文件夹。

  1. 查看快照代理的状态:

    1. 在对象资源管理器中,展开“复制”下的“本地发布”节点

    2. 右键单击发布 AdvWorksProductTrans>查看快照代理状态

    快捷菜单上的“查看快照代理状态”命令的屏幕截图。

  2. 如果快照代理状态中报告了错误,可在快照代理作业历史记录中了解更多详细信息:

    1. 在对象资源管理器中展开“SQL Server 代理”,并打开作业活动监视器

    2. 按“类别”排序,并根据类别“REPL-Snapshot”找到快照代理

    3. 右键单击快照代理,然后选择“查看历史记录”

    用于打开快照代理历史记录的选项的屏幕截图。

  3. 在快照代理历史记录中,选择相关的日志项目。 这通常位于报告错误的项目前一两行。 (红色 X 指示错误。)查看日志下方的框中的消息文本:

    屏幕截图,其中显示拒绝访问的快照代理错误。

    The replication agent had encountered an exception.
    Exception Message: Access to path '\\node1\repldata.....' is denied.
    

如果 Windows 权限未为快照文件夹正确配置,则快照代理会显示“拒绝访问”错误。 需要验证对存储快照的文件夹的权限,并确保用于运行快照代理的帐户有权访问共享。

查找日志读取器代理错误

日志读取器代理会连接到发布服务器数据库,并扫描事务日志,查找标记为“用于复制”的任何事务。然后将这些事务添加到分发数据库。

  1. 连接到 SQL Server Management Studio 中的发布服务器。 展开服务器节点,右键单击“复制”文件夹,然后选择“启动复制监视器”

    快捷菜单中的“启动复制监视器”命令的屏幕截图。

    此时,复制监视器打开:

    复制监视器的屏幕截图。

  2. 红色 X 表示发布未同步。 展开左侧的“我的发布服务器”,然后展开相关的发布服务器

  3. 选择左侧的“AdvWorksProductTrans”发布,然后在其中一个选项卡上查找红色 X,确定问题的位置。 在本例中,红色 X 位于“代理”选项卡上,表明其中一个代理遇到错误

    Replication Monitor 的“代理”选项卡上红色 X 的屏幕截图。

  4. 选择“代理”选项卡,确定遇到错误的代理

    复制监视器中日志读取器代理出现故障时显示的红色 X 标记的屏幕截图。

  5. 此视图显示两种代理:快照代理和日志读取器代理。 遇到错误的代理会出现红色的 X。在本例中,是日志读取器代理。

    双击报告错误的行,打开日志读取器代理的代理历史记录。 此历史记录提供有关该错误的详细信息:

    日志读取器代理的错误详细信息的屏幕截图。

    Status: 0, code: 20011, text: 'The process could not execute 'sp_replcmds' on 'NODE1\SQL2016'.'.
    The process could not execute 'sp_replcmds' on 'NODE1\SQL2016'.
    Status: 0, code: 15517, text: 'Cannot execute as the database principal because the principal "dbo" does not exist, this type of principal cannot be impersonated, or you do not have permission.'.
    Status: 0, code: 22037, text: 'The process could not execute 'sp_replcmds' on 'NODE1\SQL2016'.'.
    
  6. 当发布服务器数据库的所有者未正确设置时,通常会发生此错误。 这可能会在还原数据库时发生。 要验证这一点:

    1. 在对象资源管理器中展开“数据库”

    2. 右键单击“AdventureWorks2022”“属性”>

    3. 确认一名所有者存在于“文件”页下。 如果此框为空,则这可能是产生该问题的原因所在。

    数据库属性中“文件”页的屏幕截图,其中包含空白的“所有者”框。

  7. 如果“文件”页上的所有者为空,请在 数据库的上下文中打开“新建查询”AdventureWorks2022窗口。 运行以下 T-SQL 代码:

    -- set the owner of the database to 'sa' or a specific user account, without the brackets.
    EXECUTE sp_changedbowner '<useraccount>';
    -- example for sa: exec sp_changedbowner 'sa'
    -- example for user account: exec sp_changedbowner 'sqlrepro\administrator'
    
  8. 可能需要重启日志读取器代理:

    1. 在对象资源管理器中展开“SQL Server 代理”节点,并打开作业活动监视器

    2. 按“类别”排序,并根据“REPL-LogReader”类别找到日志读取器代理

    3. 右键单击日志读取器代理作业,并选择“启动作业于步骤”

    屏幕截图,其中显示用于重启日志读取器代理的选择。

  9. 通过再次打开“复制监视器”,确认发布现已同步。 如果尚未打开,通过右键单击对象资源管理器中的“复制”,可找到该监视器

  10. 选择“AdvWorksProductTrans”发布,接着选择“代理”选项卡,然后双击日志读取器代理,打开代理历史记录。 现应看到日志读取器代理正在运行,并且正在复制命令或具有“未复制事务”:

    日志读取器代理运行时无任何复制事务的屏幕截图。

查找分发代理错误

分发代理在分发数据库中查找数据,然后将其应用到订阅服务器。

  1. 连接到 SQL Server Management Studio 中的发布服务器。 展开服务器节点,右键单击“复制”文件夹,然后选择“启动复制监视器”

  2. 在“复制监视器”中,选择“AdvWorksProductTrans”发布,然后选择“所有订阅”选项卡。右键单击订阅,选择“查看详细信息”

    快捷菜单中的“查看详细信息”命令的屏幕截图。

  3. “分发服务器到订阅服务器历史记录”对话框随即打开,其中阐明了代理遇到的错误

    分发代理的错误详细信息的屏幕截图。

    Error messages:
    Agent 'NODE1\SQL2016-AdventureWorks2022-AdvWorksProductTrans-NODE2\SQL2016-7' is retrying after an error. 89 retries attempted. See agent job history in the Jobs folder for more details.
    
  4. 错误指示分发代理正在重试。 若要查找更多详细信息,请检查分发代理的作业历史记录:

    1. 在“对象资源管理器”“作业活动监视器”>中展开“SQL Server 代理”

    2. 按照“类别”对作业进行排序

    3. 根据类别“REPL-Distribution”找到分发代理。 右键单击该代理并选择“查看历史记录”

    屏幕截图,其中显示用于查看分发代理历史记录的选择。

  5. 选择其中一个错误条目,并在窗口底部查看错误文本:

    “错误”文本的屏幕截图,其中指示分发代理的密码不正确。

    Message:
    Unable to start execution of step 2 (reason: Error authenticating proxy NODE1\repl_distribution, system error: The user name or password is incorrect.)
    
  6. 此错误表示分发代理使用的密码不正确。 解决方法:

    1. 展开对象资源管理器中的“复制”节点

    2. 右键单击“订阅”>“属性”

    3. 选择“代理进程帐户”旁边的省略号 (...),并修改密码

    用于修改分发代理密码的选择的屏幕截图。

  7. 通过右键单击对象资源管理器中的“复制”再次检查“复制监视器”。 “所有订阅”下的红色 X 表示分发代理仍遇到错误

    通过右键单击“复制监视器”中的订阅“查看详细信息”,打开“分发到订阅服务器”历史记录>。 此处的错误是不同的:

    “错误”的屏幕截图,指示分发代理无法连接。

    Connecting to Subscriber 'NODE2\SQL2016'
    Agent message code 20084. The process could not connect to Subscriber 'NODE2\SQL2016'.
    Number:  18456
    Message: Login failed for user 'NODE2\repl_distribution'.
    
  8. 此错误表示分发代理无法连接到订阅服务器,因为用户 NODE2\repl_distribution 登录失败。 若要进一步调查,请连接到订阅服务器,并在对象资源管理器的“管理”节点下,打开当前的 SQL Server 错误日志

    “错误”的屏幕截图,指示订阅服务器登录失败。

    如果看到此错误,则表明登录在订阅服务器上丢失 若要解决此错误,请参阅 复制的安全角色要求

  9. 解决登录错误后,再次检查复制监视器。 如果所有问题均得以解决,可在“所有订阅”下的“发布名称”旁边看到一个绿色箭头,并且状态为“正在运行”

    右键单击订阅,即可再次打开“分发服务器到订阅服务器”历史记录,从而验证是否成功。 如果这是您首次运行分发代理程序,您会看到快照已被批量复制到订阅者:

    分发代理的屏幕截图,其中显示了“正在运行”状态和有关大容量复制的消息。

使用“合并代理”查找错误

合并代理可能需要很长时间才能复制更改。 若要确定合并复制同步过程的哪个步骤花费的时间最多,请使用 跟踪标志 101 和合并代理日志记录。 为此,请为合并代理参数使用以下参数,然后重启代理:

-T 101
-output
-outputverboselevel

注意

如果必须向 <distribution-server>..msmerge_history 表写入统计信息,请使用跟踪标志 102。

合并复制同步完成后,合并代理的示例输出如下所示:

**************************************************************
CONNECTION TIMES --> time took to establish the connection to the servers. Publisher (all connections) 156 msec   Subscriber (all connections) 32 msec Distributor 93 msec
**************************************************************
UPLOAD COUNTERS  --> upload phase (changes from the Sub to the Pub) stats MakeGeneration Time = 343 msec. InsertGenHistory Time = 31 msec. UpdateGenHistory Time = 0 msec. ProxiedMetadata Time = 0 msec.
**************************************************************
DOWNLOAD COUNTERS  --> download phase (changes from the Pub to the Sub) stats MakeGeneration Time = 219 msec. InsertGenHistory Time = 0 msec. UpdateGenHistory Time = 0 msec.
**************************************************************
RETENTION-BASED CLEANUP STATISTICS --> sp_mergemetadataretentioncleanup proc stats Publisher: Cleanup Time 281 msec MSmerge_genhistory rows cleaned up 0 MSmerge_contents rows cleaned up 0 MSmerge_tombstone rows cleaned up 0 Subscriber: Cleanup Time 187 msec MSmerge_genhistory rows cleaned up 0 MSmerge_contents rows cleaned up 0 MSmerge_rowtrack rows cleaned up 0 MSmerge_tombstone rows cleaned up 0
**************************************************************
RETRY STATISTICS Retry Time (Upload) 0 msec. Retry Time (Download) 0 msec. Total changes retried 0 Number of Iterations through rows needing retry 0 Total number of changes that failed despite retry 0
**************************************************************
PROXY METADATA QUEUE COUNTERS Queue Full: Number of Waits: 0, Total Wait Time: 0 msec
**************************************************************
Distributor-side History Logging Time = 219 msec. Number of Distributor-side History Messages Logged = 11 Subscriber-side History Logging Time = 295 msec. Number of Subscriber-side History Messages Logged = 11
**************************************************************
2013-05-28 17:24:11.820 OLE DB Subscriber '<SQL Server name>\sql2008r2': DBCC SQLPERF (NETSTATS)  2013-05-28 17:24:11.822 OLE DB Publisher '<SQL Server name>\SQL2008R2':  DBCC SQLPERF (NETSTATS)  2013-05-28 17:24:11.824 OLE DB Distributor '<SQL Server name>\SQL2008R2':  DBCC SQLPERF (NETSTATS)  NETWORK STATISTICS Server  Reads  Writes  Bytes Read Bytes Written Publisher 74  74  19112  37526 Subscriber 73  73  19032  36931 Distributor 75  75  19192  38121
**************************************************************
NETWORK STATUS Network Connection: The computer has one or more LAN cards that are active. Network link speed: Destination Incoming  Outgoing Publisher Unreachable  Unreachable Subscriber Unreachable  Unreachable Distributor Unreachable  Unreachable
**************************************************************

启用任何代理上的详细日志记录

可使用详细日志记录来查看有关复制拓扑中任何代理发生的错误的更多详细信息。 其步骤对每个代理均相同。 只要确保在作业活动监视器中选择了正确的代理即可。

注意

代理可位于发布服务器或订阅服务器上,具体取决于它是请求订阅还是推送订阅。 如果代理在被调查的服务器上不可用,检查另一台服务器。

  1. 确定要保存详细日志记录的位置,并确保该文件夹存在。 此示例使用 c:\temp。

  2. 在对象资源管理器中展开“SQL Server 代理”节点,并打开作业活动监视器

    作业活动监视器快捷菜单上的“查看作业活动”命令的屏幕截图。

  3. 按“类别”排序,并确定感兴趣的代理。 本示例使用日志读取器代理。 右键单击感兴趣的代理>“属性”

    屏幕截图,其中显示用于打开代理属性的选择。

  4. 选择“步骤”页,然后突出显示“运行代理”步骤。 选择“编辑” 。

    编辑“运行代理”步骤所选项的屏幕截图。

  5. 在“命令”框中,开始新行,输入以下文本并选择“确定”

    -Output C:\Temp\OUTPUTFILE.txt -Outputverboselevel 3
    

    可根据你的偏好修改位置和详细级别。

    屏幕截图,其中显示作业步骤属性中的详细输出。

    添加冗长输出参数时,以下问题可能会导致代理程序无法正常工作,或者 outfile 文件缺失:

    • 存在短划线变成连字符的格式问题。

    • 该位置在磁盘上不存在,或者运行代理的帐户没有权限写入指定的位置。

    • 最后一个参数与 -Output 参数之间缺少一个空格。

    • 不同的代理支持不同的详细级别。 如果启用详细日志记录但无法启动代理,请尝试将指定的详细级别降低 1 级。

  6. 右键单击“代理”>“停止作业于步骤”来重启“日志读取器代理”。 从工具栏中选择“刷新”图标来刷新。 右键单击“代理”>“启动作业于步骤”

  7. 查看磁盘上的输出。

    输出文本文件的屏幕截图。

  8. 若要禁用详细日志记录,请按照之前的相同步骤来删除先前添加的整个 -Output 行。

获取帮助

参与编辑 SQL 文档

你是否知道你可以自行编辑 SQL 内容? 你如果这样做,不仅可以帮助改进我们的文档,还可以获得页面贡献者的殊荣。

有关详细信息,请参阅 “编辑Microsoft Learn 文档