
做数据库的人早晚会碰到一个需求两台机器上的数据要保持一致。我以前负责的一套系统就是这种结构主库在本地机房异地业务方需要一份从库做查询和报表输出两边不在同一个局域网只能走互联网同步。当时用的就是 SQL Server 2014 的主从数据库订阅和发布也就是 SQL Server 复制把“异地订阅”这条路完整趟了一遍。网上讲复制的教程不少但大多默认两台服务器在一个内网真正把互联网场景下的配置细节、网络规划、踩坑点讲清楚的并不多。这篇文章把我当时的完整配置过程和排查经验整理出来给正准备搭这套架构的同行做个参考。1. 方案选型为什么异地互联网场景我最终选了事务复制1.1 SQL Server 复制三种模式的本质区别SQL Server 复制不是只有一种模式它分了快照复制、事务复制、合并复制三种很多人第一次接触时容易搞混。简单来说快照复制就是定时把整份数据拍一张照片扔给你事务复制是捕捉数据库日志里的每一次增删改然后把这些变更一条条搬到订阅端合并复制则是允许多个端都能改数据最后再合并统一。我当时的需求非常明确主库负责生产和写入从库只读要求数据尽量实时不能接受每天只同步一次。快照复制对数据量小、变更不频繁的系统或许够用但我的主库虽然单表不算特别大合计起来也有几十 GB快照复制每次全量拉一遍根本不现实。合并复制则需要处理两端冲突纯粹是给自己找麻烦不符合主从的场景。事务复制通过日志读取器扫描主库事务日志然后把变更分发到订阅端实时性非常好看起来就是最合适的方案。事务复制有一个特别大的优势是其他方案替代不了的它的增量同步是基于日志的所以即使网络偶尔抖动分发的命令也会在分发数据库中排队等网络恢复后继续推送不会因为一台机器临时不可用就直接导致数据永久丢失。这一点在互联网异地环境下非常重要公网链路的稳定性远不如机房内网偶尔断个几十秒甚至几分钟都是常态复制机制本身的容错能力能帮你挡掉很多麻烦。1.2 复制、镜像、AlwaysOn、日志传送到底该用哪个我整理需求的时候其实是把当时 SQL Server 2014 能用的几种数据同步方案都过了一遍。镜像和 AlwaysOn 可用性组是很多人第一个想到的它们确实也能实现主从同步但在异地互联网场景下各有各的问题。方案同步粒度异地互联网适配性主要痛点事务复制事务级增量高需要有主键配置稍复杂但容错最好数据库镜像页级重做低2014 已标记为过时公网证书配置麻烦断线重连体验差AlwaysOn 可用性组页级重做中2014 的 AG 测异地读写分离很不顺手对版本和带宽要求高日志传送日志备份传递中只能做库级恢复式同步日志断链就会中断恢复很痛苦我不否定 AlwaysOn 的价值但如果是在 SQL Server 2014、标准版、跨互联网这种组合条件下事务复制几乎可以说是最务实的方案。尤其需要注意版本因素2014 的 AlwaysOn 可用性组在企业版里算比较成熟了但标准版根本没有可用性组可用而事务复制在标准版上就可以做发布和订阅这对很多没有企业版授权的公司来说是一个决定性的理由。还有一个容易被忽略的点复制对网络的要求不像 AlwaysOn 那么苛刻。AlwaysOn 需要持续保持节点间的通信和日志重做数据同步的稳定性高度依赖网络质量复制则通过 SQL Agent 作业驱动偶尔断网后它会不断重试把断网期间的数据从分发库继续推过去。对互联网这种不保险的网络环境来说多一层缓冲就多一分安全感。1.3 拓扑设计分发服务器应该放在哪里复制有发布服务器、分发服务器、订阅服务器三个角色。最简单的拓扑是发布服务器和分发服务器用同一个实例这也是我当时选择的方案。因为如果发布端和分发端分处两地那么快照文件和事务命令需要跨公网在分发服务器和发布服务器之间来回传递等于完全抵消了复制自带缓冲的优势还会加重公网负担。正确的做法是让分发服务器和发布服务器在一起或者干脆就是同一台机器。分发数据库是复制的“中转站”发布端产生的变更命令先落在这里再由分发代理推送到订阅端。把这个中转站放在主库本地可以保证复制的数据链路是“主库 - 本地分发库 - 公网 - 订阅库”出问题的环节只有一个公网链路排查起来思路非常清晰。订阅服务器的位置不用多做纠结它就在异地只要能通过网络访问到发布端的 SQL Server 实例和快照资源就行。至于数据库层面的拓扑我是把发布库和订阅库的名称保持一致的这虽然不是强制的但能让你在写监控脚本和分析报错时少一层心智负担。2. 环境规划与底线检查2.1 版本、服务账号、服务器命名这三件事必须提前定你准备要配置复制的时候最重要的一步不是打开 SSMS 点向导而是先做环境检查。第一是版本权限SQL Server 2014 的标准版就支持事务复制发布这一点比 AlwaysOn 的版本门槛低很多但你要确认自己的实例不是 Express 版Express 版只能做订阅端不能做发布端我当时差点在这个地方翻车。第二是 SQL Server 代理服务复制靠的是代理作业这个服务必须设置成自动启动而且要用一个有权限的 Windows 账户运行不要用 LocalSystem 去跑否则后面访问网络共享、连接订阅端实例时会遇到稀奇古怪的权限报错。推荐的配置是给 SQL Agent 单独建一个 windows 账号并赋予 SQL Server 实例的系统管理员权限这样快照代理和分发代理运行起来会顺畅很多。第三是服务器名字这一点真的想强调一下很多人在配置过程中把服务器重命名过结果复制里的系统表记录的还是旧的服务器名所有代理作业全部连不上最后只能把复制整个删了重建。SQL Server 复制会把服务器名称写进发布和订阅的相关系统表你必须在创建复制之前就把服务器名定死。如果确实提前重命名过请用sp_dropserver和sp_addserver把旧的实例名处理干净再重启 SQL 服务。2.2 快照文件夹的三种落地方案公网共享 SMB 是下策复制初始化时快照代理会把表结构和数据生成到快照文件夹里订阅端再从里面读取。本地复制很容易直接用一个\\服务器名\共享目录就搞定异地订阅就不一样了这个共享文件夹必须能让异地的订阅服务器访问到问题随之而来。我见过很多人的第一反应是把文件共享的 445 端口从路由器映射到公网我只能说千万别这么干。公网直接暴露 SMB 服务是非常危险的事扫描器天天在外面扫 445 端口一旦中招后果不堪设想。即使在有防火墙的情况下445 跨公网传输速度也很慢大表初始化的时候能把你急死。更靠谱的方案有三种第一种是在发布属性里配置 FTP 快照快照代理把生成的文件传到 FTP 服务器订阅端从 FTP 下载第二种是使用备份初始化先在主库做一次完整备份把备份文件通过 FTP 或网盘传给异地在订阅端还原然后让订阅从这个备份的 LSN 位置开始同步第三种是借助内网穿透工具把发布端某些需要的端口映射出去实现有限度的访问而不是直接把 SMB 裸奔到公网。我当时的做法是第二种为主。一次性全量数据用备份还原的方式初始化后续增量走事务复制这样既绕开了快照文件跨公网传输的头痛问题又不影响复制的实时增量能力。如果你确实想要全自动快照初始化FTP 快照是相对安全且省事的选择下文我会专门讲配置细节。2.3 表结构、大表评估、发布库状态提前过一遍清单事务复制对表结构有一个硬性要求发布的每张表必须有主键。这是为了保证订阅端在应用 insert/update/delete 命令时能准确定位到对应行。如果有些历史遗留表没建主键要么补一个主键要么干脆不把它放进发布里。还需要评估的是大表的初始化时间。假设一张表 10 GB备份初始化和快照初始化都要经过网络传输哪怕你带宽是百兆专线也需要十几分钟。更麻烦的是初始化期间主库日志文件会不断增长因为日志读取器代理要从日志里读取事务并且等待订阅端应用如果订阅端迟迟没有完成初始化日志读取器会积压大量未分发的事务导致主库日志快速增长。所以最好选择业务低峰期做初始化。发布数据库的状态也要注意如果发布库上还开着其他特别频繁的 DDL 操作比如有人天天删索引、重建表复制代理的作业容易报错。生产环境配置复制前先跟开发团队打好招呼发布表的 DDL 操作不能太随意SQL Server 复制的 DDL 同步机制虽然支持不少 ALTER TABLE 操作但把表删了重建这种事情肯定是承受不了的。3. 发布端配置实操3.1 配置分发服务器让主库兼任分发角色SSMS 里配置分发的路径是在“复制”节点上右键选择“配置分发”。向导会让选择分发服务器我直接把本地实例作为分发服务器这个最省心。接下来会问你分发数据库的存放位置建议不要放 C 盘把数据文件和日志文件指到独立的数据盘因为分发库在事务量大时会持续增长分配一个有规划的空间能避免后面频繁维护磁盘空间。还要设置快照文件夹的路径这就是你初始化用的工作目录。如果选择用备份初始化这个文件夹只是用来存放快照相关信息不会真的跨公网传输全量数据所以本地磁盘路径就够了。如果用 FTP 快照快照文件夹路径是作为中间缓存存在的代理生成的文件会从本地这个路径上传到 FTP。TSQL 方式的脚本大概是这样的USE master; EXEC sp_adddistributor distributor NPUB01; EXEC sp_adddistributiondb database Ndistribution, data_folder ND:\MSSQL\Data, log_folder ND:\MSSQL\Log; USE distribution; EXEC sp_adddistpublisher publisher NPUB01, distribution_db Ndistribution, working_directory ND:\ReplData, security_mode 1;sp_adddistributor是注册分发服务器sp_adddistributiondb创建分发数据库sp_adddistpublisher则是把发布服务器和分发服务器关联起来并指定工作目录。security_mode 1表示使用 Windows 身份验证连接发布服务器如果你的环境必须用 SQL 登录可以改成0并补上login和password但我个人更建议同一台机器的组件之间用 Windows 身份验证避免明文密码散落在各处。3.2 新建事务发布表和对象的选择要克制分发配置完成后在“本地发布”节点上右键选择“新建发布”。选择发布数据库后发布类型务必要选“事务发布”。分配完要发布的表之后向导会问你“项目类型”和是否要筛选数据。筛选包含行筛选和列筛选如果你的从库只需要某几张表甚至只需要部分列在这里就可以通过筛选功能过滤掉不必要的数据减少同步的数据量。这里我要给一条实际经验能少发布就少发布不要顺手把所有的表都勾上。发布对象越多日志读取器和分发代理的压力越大排查问题的时候要排查的表也越多。而且每张表都有自己的复制命令元数据积压起来占用空间很大。我遇到过有同事一把梭全选结果几十张表全部发布后来想单独重置一张表的同步状态干扰面就特别大。安全性设置页面会问要运行哪些代理进程你按需求选上“快照代理”和“日志读取器代理”。快照代理的调度计划建议选“手动”不要默认让它每小时跑一次因为事务复制的日常同步根本不依赖定时快照定时拍快照纯属浪费资源还干扰订阅初始化。发布名称可以定义一个便于识别的名字比如Pub_MyDB_Trans这个名称以后会在订阅端出现建议语义化清晰一点。3.3 发布属性里的关键配置FTP 快照和备份初始化声明发布创建完之后还要回到发布属性里确认几个关键项。右键发布名称打开“发布属性”在“快照位置”页面里可以看到默认选的是“将文件放入默认文件夹”。如果你打算用 FTP 快照这里选择“使用 FTP”然后填写 FTP 服务器地址、端口、登录账号密码和对应的快照文件路径。这里有个容易踩坑的细节当你选择 FTP 快照之后快照代理仍然会先在本地工作目录生成快照文件然后再上传到 FTP 服务器的指定目录。所以本地工作目录的磁盘空间和权限依然是必须要满足的不是选了 FTP 就不需要本地目录了。如果你打算用备份初始化不打算在公网上传快照文件那么发布属性里的快照位置保持默认即可。创建订阅的时候初始化方式选择“从备份初始化”并在订阅端先手工把备份还原好。这个“从备份初始化”其实是有一个对应的 TSQL 参数的叫sync_type Ninitialize with backup界面操作和脚本都能支持。4. 订阅端配置与初始化4.1 推送订阅和请求订阅异地场景到底选哪个创建订阅前先得把“推送订阅”和“请求订阅”的机制搞清楚。推送订阅是分发代理运行在分发服务器上由主库这边主动把数据推给订阅端请求订阅是分发代理运行在订阅服务器上由从库这边主动来拉取数据。特点推送订阅请求订阅分发代理位置分发服务器主库侧订阅服务器从库侧配置集中度主库统一管理状态监控集中每个订阅端各自管理代理入站要求主库必须能访问订阅端订阅端必须能访问主库公网场景限制主库需要能连到订阅端 SQL 端口订阅端需要能连到主库 SQL 端口如果你做主库侧的网络策略比较开放能顺利连接到异地的订阅端 SQL Server 实例那么推送订阅更好管理所有代理作业都集中在你熟悉的这台机器上用复制监视器一眼就能看全。如果你把主库保护得很严公网入站端口都不开只允许从库主动出站连接主库那么请求订阅更符合你的网络现实。我当时主库侧有专线能直接访问异地订阅端的 1433 端口所以选择了推送订阅方便一把梭监控所有状态。这里没有绝对的优劣完全是看网络策略和运维习惯。4.2 手工准备订阅库备份还原先走一步用备份初始化时订阅端的准备工作是在创建订阅之前就要完成的。先去主库上对发布库做一次完整备份注意备份期间不要出现分布式事务或未提交的长事务保证备份是一个一致性快照。BACKUP DATABASE [MyDB] TO DISK ND:\Backup\MyDB_Full.bak WITH COMPRESSION, INIT;压缩备份能显著减少文件体积跨公网传输的时候非常划算。把备份文件传到异地订阅服务器上然后用 RESTORE 命令还原。还原时数据库文件路径要按订阅端本地磁盘分布来调整千万别直接把备份里的路径原样套上来。RESTORE DATABASE [MyDB] FROM DISK ND:\Backup\MyDB_Full.bak WITH REPLACE, MOVE NMyDB TO ND:\MSSQL\Data\MyDB.mdf, MOVE NMyDB_log TO NL:\MSSQL\Log\MyDB_log.ldf;还原完之后先确认库能正常打开然后不要急着在订阅端做任何写操作。SQL Server 复制要求订阅表的数据完全由发布端驱动如果你在订阅端手动改了数据后面同步时极大概率会出现主键冲突或更新影响行数为 0 的报错。4.3 创建推送订阅并用备份文件完成初始化在发布服务器 SSMS 的“本地发布”下右键你刚才创建的发布名称选择“新建订阅”。订阅服务器选择异地服务器订阅数据库选择你刚还原好的MyDB。如果下拉列表里没出现这个库先确认连接串里拼的服务器名和库名正确。进入“初始化订阅”页面时把“初始化方式”选成“立即初始化”在初始化方式的下拉里选择“使用备份文件”。为了避免理解偏差我补充一个判断标准只要你已经在订阅端手工还原了数据库并且希望复制代理从备份文件的 LSN 位置开始继续同步增量就不要选那个“快照初始化”而要选“从备份初始化”。安全设置页面中会要求提供“分发代理”使用的 Windows 账户或 SQL Server 账户它负责连接订阅服务器和订阅数据库。这个账号至少要在订阅端有db_owner权限否则应用事务命令时会一直报权限错误。代理计划就按默认连续运行SQL Server 复制会自己处理重连和重试逻辑不需要你每天去手动跑。最后一步确认创建后SSMS 会提示你要不要立即启动代理选“是”。订阅创建完成后第一时间去复制监视器里查看“分发到订阅服务器”的代理历史正常情况下状态应该是“正在运行”或“已完成”如果出现红色的失败记录再接着往下看排查部分。4.4 验证同步是否真的在工作配置完成不代表万事大吉验证环节不能省。我通常先看发布端的事务积压情况在主库执行一条系统存储过程USE [MyDB]; EXEC sys.sp_replcounters;这个命令会返回每张已发布表当前的事务复制进度重点关注两个值pending_command_count和latency。pending 的数字越大说明积压的命令越多网络或订阅端可能卡住了latency 表示延迟时间单位是秒正常情况下应该非常小如果你发现延迟到了几百秒甚至上千秒那肯定哪里出了问题。然后在订阅端抽查数据对已发布的表做一次SELECT看看数据量和主库是否一致再对比几条最新记录确认增量确实在持续同步。我还会顺手做一个小测试在主库建一张已经包含在发布里的测试表插入一条带时间戳的记录过几十秒去订阅端查看这条记录是不是已经过来了。这个测试要提前和业务团队说一声避免误伤生产数据。5. 异地互联网场景下的六个坑与应对方案5.1 服务器名解析不了代理报错说连不上对端异地订阅最常见的问题就是代理作业的日志里写着“无法将名称 XXXX 解析为服务器”。原因是复制代理在启动时是严格按照创建订阅时填写的服务器名去解析连接的如果这个名字在代理运行的机器上无法通过 DNS 解析连接就直接失败。解决办法不是去改复制配置而是在运行代理的服务器 hosts 文件里把对端的公网 IP 和主机名映射关系写上去。比如你的订阅服务器主机名是SUB01公网 IP 是203.0.113.5就在主库服务器的C:\Windows\System32\drivers\etc\hosts里加一行203.0.113.5 SUB01反过来如果订阅端是请求订阅也要在订阅端服务器的 hosts 里加上发布端的公网解析。这一步看着很土但在没有内部 DNS 的环境里是真管用公网环境里主机名解析本来就是最容易出问题的一环。5.2 公网端口映射安全边界要守好异地订阅至少要打通 SQL Server 实例的 1433 端口这是数据库之间通信的根本。对你的路由器或者云安全组来说放行 1433 端口并限定来源 IP 是最基本的操作千万不要把端口完全开放给整个公网只允许你订阅服务器的公网出口 IP 访问就好。如果订阅端 IP 是动态的那就配合 DDNS 动态域名把防火墙策略绑在域名或 IP 的定时更新上。如果用了 FTP 快照还要在 FTP 服务器上放行 FTP 控制端口和数据端口并配置好账号对快照目录的读写权限。再次强调不要开放 445 端口到公网SMB 协议跨公网的安全风险太高初始化快照的方案那么多没必要在安全上冒这个险。5.3 带宽延迟的适应与分发代理参数调优异地环境普遍带宽小、延迟高如果主库的事务量很大复制可能会经常出现积压。这时可以考虑对分发代理作业的命令行参数做一点调整。在 SQL Server 代理里找到分发代理作业编辑作业步骤在命令行的后面可以追加参数常用的有-CommitBatchSize和-CommitBatchThreshold。这两个参数决定了分发代理每个事务提交批次的大小。默认值针对局域网环境更激进延时高的公网链路如果批量太大容易出现大量超时回滚把批大小适度调小比如-CommitBatchSize 100 -CommitBatchThreshold 500能减少单个批次在公网链路上排队的时间同步更稳代价是吞吐量会稍微下降。不要拿这两个参数一顿乱调先观察再改每次只动一个变量。5.4 快照初始化卡顿老实用备份初始化如果你还是选择了快照初始化在公网环境大概率会遇到快照文件无法下载或者下载到一半失败的情况。这是因为快照文件往往很大而公网链路传输大文件的稳定性很难保证。我见过有人让快照代理反复重试结果每次都断在同一个大表上白白浪费大量时间。这种情况下最务实的解决方案就是改用备份初始化也就是我在第 4 章讲的那套流程备份发布库手工还原到订阅端让复制从备份位置接着同步。备份文件传输同样走公网但它是一次性、可断点续传的比快照代理反复重试靠谱得多。日常维护中如果订阅端数据损坏需要重建我基本不会去依赖快照直接用最近一次完整备份加日志备份还原后重新初始化订阅流程更干净。5.5 发布表的 DDL 变更会同步但别乱来事务复制默认支持把发布表的 ALTER TABLE 变更同步到订阅端比如追加一个可空列、调整字段长度这些操作在主库执行后复制会自动把 DDL 命令分发给订阅端。不要小看这个能力有些 DBA 以为加列后还要去订阅端手工改表结果两边结构不一致后面的 DML 命令直接报错。只要你能保证从库结构和主库一致数据库复制就能顺利跑。但这不代表什么 DDL 都能乱来。比如你把一张发布表删除重建复制会直接罢工。加了新表也不会自动加入发布需要手动把新表添加为发布项目或者重新生成发布。我的习惯是给开发团队写清楚一份“发布库 DDL 操作红线清单”哪些底线不能碰这样能把很多维护成本扼杀在源头。5.6 复制监视器和延迟指标日常值班就靠它们复制状态不是配好以后就一直能安稳睡大觉的公网环境随时可能出现抖动、掉线、积压。SSMS 自带“复制监视器”功能打开本地发布的节点可以看到每个订阅的同步状态、延迟时间、性能指标还有各个代理的历史记录和报错信息。我值班的时候基本只看两个东西一是代理是否失败二是延迟是否超过预设阈值。还可以写一个简单的监控 SQL定时跑一次把复制延迟和失败状态发到钉钉或企业微信告警。查询分发历史表就能拿到最近状态USE distribution; SELECT TOP 20 h.time, h.comments, h.status, s.name AS agent_name FROM dbo.MSdistribution_history h LEFT JOIN dbo.MSagent_profiles p ON h.agent_id p.agent_id LEFT JOIN dbo.MSagents s ON h.agent_id s.id ORDER BY h.time DESC;只要把这个脚本做成每分钟执行一次把status 6之外的记录都当异常处理就能在复制真正出问题的时候第一时间收到提醒不用等用户来投诉数据不对。6. 常见故障与排查速查6.1 “无法访问快照文件夹”其实不是网络问题而是权限问题有一次配置完成后快照代理一直报“无法访问文件夹”我一开始以为是公网网络不通排查了半天最后发现是快照代理的运行账户对工作目录没有写权限。只要代理进程没有对快照目录的 NTFS 权限它连本地目录都可能访问失败更别提交互到异地了。遇到这个报错的时候先别急着怀疑网络先把代理运行账户、快照目录的共享权限和 NTFS 权限逐层检查一遍。最简单粗暴的验证方式是把运行代理的账户手动添加到目录的完全控制列表里然后再跑一次快照如果是权限问题这个报错立刻就会消失。6.2 分布代理报“进程无法连接到 Subscriber”这个报错的本质是分发代理连接订阅端时失败了。可能的原因有很多订阅端 1433 被防火墙挡了、主机名解析失败、订阅端 SQL Server 服务停了、或者认证方式不对。我从经验出发的排查顺序是先用telnet测对端 1433 通不通再确认 hosts 解析最后检查订阅端实例是否能正常接受外部连接。有时候你在订阅端重启了一次 SQL Server 服务会导致部分代理会话瞬间断开过一会它会自己重连这种短暂的报错不一定需要人工干预。我判断的标准很简单看下一次代理运行记录里是不是成功了只要历史记录里最近的运行时间显示“成功”前面那次报错就可以忽略。6.3 日志读取器代理卡住主库日志疯狂生长日志读取器代理的任务是把主库事务日志里的变更读出来并写入分发数据库。如果它卡住了主库的日志文件会持续增长甚至把磁盘占满。常见原因包括发布了不含主键的表、发布对象存在不支持的数据类型、代理运行账户权限丢失、或者主库处于特殊状态。一旦发现主库日志增长异常先看日志读取器代理的历史报错。如果是权限问题重新配置代理账户并跑一次如果是表结构问题把不支持的发布项删掉重新建发布。修复后记得对主库做一次日志备份把日志文件收缩回正常大小。6.4 订阅端缺数据重初始化是最终手段但别乱用同步过程中如果订阅端由于某种原因滞后太多或者出现无法修复的错误最常见的兜底手段是重新初始化订阅。在 SSMS 里右键订阅“重新初始化”即可。这个操作的代价是订阅端会先用快照或你指定的备份整体重建一遍数据数据量大时耗时很长期间订阅端处于不可用状态所以尽量选在业务低峰期操作。重新初始化之前还要看一下发布属性的“允许从备份初始化”和“允许将非初始化的订阅标记重新初始化”配置有些默认限制可能导致你操作的时候找不到对应的选项。我的建议是能通过增量修复的就不要重初始化重初始化是最后的手段而且是“保留现场”和“尽快恢复”两个目标之间的取舍。6.5 分发数据库膨胀别忘记清理历史分发数据库是复制命令的暂存地所有事务命令在推送给订阅端后仍会保留一段时间用于历史追踪和失败重试。默认的保留期可能比较长导致distribution库不断变大。处理方式是定期调整发布属性的“历史记录保留期”和“分发保留期”并对过期记录做清理。USE distribution; EXEC dbo.sp_distribution_cleanup distribution Ndistribution, min_distretention 0, max_distretention 24;这个存储过程会把超过最大保留期的事务历史和代理历史清理掉。生产环境我一般把事务保留期设置为 24 到 72 小时既保证有足够的重试窗口又不至于让磁盘无限膨胀。6.6 一张速查表对应的常见问题处理路径现象优先排查方向处理手段快照代理报无法访问文件夹代理账户权限、共享权限修正目录权限重跑快照代理分发代理连不上订阅端1433 端口、hosts 解析、SQL 认证测端口、加 hosts、检查订阅端状态主库日志增长异常日志读取器代理是否卡住查代理报错修复后做日志备份订阅端查询数据陈旧订阅是否过期、分发代理是否停止看复制监视器重启代理必要时重初始化新表不同步新表未加入发布添加新项目到发布或者重建发布订阅端数据被手工修改主键冲突或更新行数为 0恢复订阅端数据或者重新初始化订阅这套速查表基本覆盖了我在维护期间遇到的绝大多数情况照着思路排查通常能很快定位问题不至于一上来就重初始化、删库重建把事情越搞越大。我个人在实际操作中的体会是SQL Server 复制这套东西配置过程并不算难真正的难点全在“公网环境的不确定性”上。网络抖动、IP 漂移、防火墙策略调整、域名解析失效这些才是异地订阅最大的敌人。所以我最后想说的一句话是不要以为发布和订阅建好就结束了运维阶段一定要把监控告警做起来把初始化和重初始化的流程文档化这样每次出问题都能按照预案快速处理而不是临时抱佛脚。希望这篇整理能帮你少走几条弯路。