凌晨两点,群里发来一条消息:一台业务服务器的配置文件目录被误覆盖了,第二天一早要验收。我第一反应是去翻备份,结果发现当时用的备份策略是每天凌晨 1 点跑一次脚本拷贝,而误覆盖发生在当天下午。也就是说,最近的可用恢复点也在十几个小时之前,中间写进去的新数据全部没救了。那次之后我把“备份”重新拆成了两个需求:一是数据要实时出现在另一台机器上,二是每次错误操作发生之前的样子都能找回来。今天这篇就是讲我最后落地这套方案的全过程——Windows Server 之间做文件实时备份,工具选 Syncthing,再给同步文件夹打开历史版本功能,专门当“后悔药”用。读完你会清楚它适合什么场景、怎么安装部署、版本控制参数怎么调,以及实际跑起来之后会踩到哪些坑。
1. 先弄清楚:你需要的到底是不是“实时备份”
1.1 定时备份的盲区到底在哪
做 Windows Server 运维的人对 Robocopy 加计划任务这套组合应该都不陌生。每台业务服务器上放一个脚本,每天凌晨把指定目录 COPY 到文件服务器或另一台机器,逻辑很简单,成本也低。但它的本质是定时全量拷一遍,不是实时同步。这意味着两次任务之间的窗口内,任何一次误删除、误覆盖、勒索病毒加密,都可能直接落在盲区里。你恢复出来的文件,永远停留在“上一次任务成功执行”的那个时间点,之后的几百次修改全部丢失。
如果业务目录是只读的、一天就落几个文件,这点盲区无所谓。但一旦目录里有正在生成的新文件、频繁改动的配置、团队协作的共享文档,这个恢复点目标(RPO)就可能长达十几个小时。对生产环境来说,这是不可接受的。所以第一步不是急着选软件,而是要承认一个事实:你的需求不是“每天备份一次”,而是“文件一变,另一台机器立刻有最新版本”。
1.2 实时同步不是“网盘自动上传”
很多人听到实时备份,第一反应是国产网盘的自动同步文件夹,或者服务器上装一个云盘客户端把目录同步上去。这两种做法和 Windows Server 之间做实时同步有本质区别:网盘走的是中心化链路,文件先上传到别人的服务器,再由目标设备下载,中间有一层第三方基础设施。且不说带宽和延迟,企业场景里把业务数据放到第三方平台,光合规和隐私就是个大问题。
Syncthing 的模型完全不同。它是点对点同步,两台 Windows Server 之间可以直接通信,数据不经过任何中间服务器。传输过程默认走 TLS 加密,说明白一点就是“两台服务器之间私聊”。这也是我在内网服务器互备场景里优先考虑它的原因:没有外部依赖,没有中转设备,断外网也能在两台机器之间正常同步。
1.3 历史版本为什么能当“后悔药”
实时同步解决的是“另一台机器也有最新数据”,但同步本身解决不了“数据被改坏了”的问题。因为同步会把误删除、误覆盖这些操作原样复制到对端——你删了,对端也跟着删,镜像不会替你分辨哪个操作是故意的、哪个是手滑。
所以必须再加一层“历史版本”机制。Syncthing 里的文件版本控制,简单说就是:当文件即将被新版本覆盖或者被删除时,先把旧版本转存到专门目录,再执行真正的覆盖/删除。这样不管你是改错了一个配置,还是整目录被删了,都能从旧版本里找回某个时间点的文件。把这个机制用好,才是真正的“后悔药”,否则实时同步只是把错误复制得更快而已。
2. 方案选型:为什么是 Syncthing 而不是 Robocopy 和 DFS
2.1 传统 Robocopy 加计划任务的三宗罪
先别急着否定 Robocopy,它单机全量拷贝的性能和稳定性没问题,但在“实时互备”这个目标下,它有三个硬伤。
第一是无中间状态。Robocopy 的/MIR镜像模式会把源端删除的文件连同目标端的一起删掉,如果源端误删,目标端几乎同步跟着殉葬,而且没有任何版本可言。就算不用/MIR而用普通复制,被覆盖的文件旧内容也被直接换掉了,没有后悔余地。
第二是备份窗口内的数据一致性差。复制大目录的时候,文件随时可能被写入,起跑时读到的内容和跑完时的内容很可能不是同一个版本。真要保证一致性,你得把业务停下来才能 COPY,这在生产环境根本没戏。
第三是暴力全量 COPY 对服务器 IO 的冲击。目录里文件一多,每次跑任务都相当于把整个目录重新拖一遍,系统盘和网络链路都跟着遭殃。所以“定时全量拷贝”的逻辑框架本身就撑不起高频、大目录的实时备份需求。
2.2 DFS-R、VSS、云同步这些方案的适用边界
微软自家有 DFS-R(分布式文件系统复制),在域环境下配置几台服务器之间的文件复制很方便,还支持多主复制。但它更侧重于“多节点一致”,实时性虽然比脚本强,却存在复制延迟和冲突处理的问题。一旦多个节点同时改了同一个文件,合并逻辑会让你头疼,历史版本也不是你想查就能直观查到的。
Windows 的卷影副本(VSS)能提供不错的文件历史快照,可它毕竟是本机快照,解决的是“文件被改坏后本机回滚”,解决不了“整机磁盘坏了、机器没了”这种跨设备容灾问题。我的看法是,VSS 和 Syncthing 并不冲突,甚至能互补,但 VSS 不能替代异机实时备份。
网盘类工具前面说过,走第三方基础设施,合规和带宽都不适合服务器内部互备。至于纯靠 FileSystemWatcher 自己做文件监听加复制,小规模目录可以玩一玩,文件一多,状态管理、增量校验、并发处理全是坑,后期维护成本远超预期。
2.3 Syncthing 的真实收益
Syncthing 是开源项目,用 Go 写的单文件程序,部署极其轻量。它的文件监听机制能秒级感知目录变化,同步时走块级增量:一个大文件只改了几 KB,它只传输这几个块,不会整个文件重传。这对服务器间的带宽和 IO 压力都非常友好。
另外它还天然支持“仅发送”“仅接收”这样的同步方向,非常适合备份拓扑。再叠加内置的三种文件版本控制策略,相当于一台机器完成了“实时同步”和“历史回滚”两件事。用一张表来对比会更直观:
| 对比维度 | Robocopy + 计划任务 | DFS-R | Syncthing |
|---|---|---|---|
| 实时性 | 取决于计划周期 | 较高,仍有延迟 | 秒级监听触发 |
| 历史版本 | 需自行轮转脚本 | 不直接提供 | 内置三种策略 |
| 部署复杂度 | 低 | 中,依赖域环境 | 低,单文件运行 |
| 跨公网能力 | 需自行处理 | 较麻烦 | 天然支持 TLS 直连 |
| 增量传输 | 基本全量 COPY | 有增量机制 | 块级增量,效率高 |
我选它,核心就是“轻量、实时、有历史版本、无中心依赖”这四句话。它不是万能的,但在我遇到的大部分 Windows Server 互备场景里,它比那套老掉牙的脚本方案可靠得多。
3. 部署准备:版本挑选、端口规划与运行账号
3.1 Windows Server 版本兼容性与下载
Syncthing 的官方发布包在官网的 Download 页面可以找到,下载 “windows-amd64” 的压缩包即可,解压后就是一个 syncthing.exe,不依赖 .NET 运行时。从 Windows Server 2008 R2 一直到现在主流的 Windows Server 2016、2019、2022、2025,我都见过有人跑,兼容性相当广。
这里有个基于实际经验的提醒:如果还在用很老的操作系统版本,比如 Windows Server 2008 R2,别一上来就追 Syncthing 最新版。新版二进制所用的基础库可能要求较新的系统补丁,稳妥的做法是在发布页面选择两三年左右、还支持该系统的历史版本。服务器系统是老爷机的时候,“最新版”未必是“最合适版”。
另外 Syncthing 的管理界面是 Web 页面,如果部署的是 Windows Server Core 这种不带桌面环境的版本,也没问题,只要网络能通,用内网其他机器的浏览器访问端口就行。这也是它讨人喜欢的地方——不挑操作系统形态。
3.2 端口清单与防火墙策略
Syncthing 运行后主要涉及三个端口,部署前最好先规划清楚:
| 端口 | 协议 | 用途 | 是否必须 |
|---|---|---|---|
| 8384 | TCP | Web 管理界面 | 管理需要 |
| 22000 | TCP | 设备之间数据传输 | 必须放行 |
| 21027 | UDP | 局域网内设备自动发现 | 可选 |
两台 Windows Server 在同一局域网内的话,最核心就是把 TCP 22000 放行。可以用 PowerShell 建防火墙规则:
New-NetFirewallRule -DisplayName "Syncthing 22000" -Direction Inbound -Protocol TCP -LocalPort 22000 -Action Allow New-NetFirewallRule -DisplayName "Syncthing 21027 UDP" -Direction Inbound -Protocol UDP -LocalPort 21027 -Action Allow如果两台服务器之间有防火墙设备或安全组,也要同步放行这个端口。跨公网部署时,22000 TCP 需要在路由上做端口映射,Syncthing 会优先尝试直连,连不上时才走公共中继。对于纯内网互备,我习惯在“设置 → 连接”里关闭全局发现和公共中继,只保留本地发现和直连,避免设备信息暴露到公网发现服务,也更符合内网隔离的安全习惯。
3.3 目录规划:数据目录、版本目录、日志目录分开
我第一次部署时偷懒,把同步数据、版本文件、日志全堆在 C 盘,结果运行一段时间后版本文件越攒越多,系统盘告警。所以目录规划一定要放在部署第一步,而不是等爆了再改。
我现在的标准布局是:
- 同步数据目录:
D:\SyncData,放真正需要跨服务器同步的业务目录 - 版本目录:
D:\SyncVersion,放历史版本文件,建议和同步数据分开在不同磁盘 - 日志目录:
C:\Syncthing\logs,给 NSSM 记录服务输出日志
版本目录单独分出来的理由很充分:如果版本目录和同步数据在同一个文件夹内,Syncthing 会通过.stversions这种默认机制自动识别并避免递归同步,但版本文件的体积膨胀会导致同步文件夹整体看起来越来越大,维护时容易产生误判。独立磁盘后,版本增长对主数据目录的影响就完全透明了,也方便单独做快照保护。
3.4 用 NSSM 把 Syncthing 注册成 Windows 服务
Syncthing 双击 exe 就能跑,但那只是前台进程,关了窗口就没了。Windows Server 上要当正式服务用,必须注册成开机自启、崩溃自动拉起、后台运行的服务。我用的是 NSSM,一个老牌 Windows 服务封装工具。
把 syncthing.exe 解压到C:\Syncthing后,执行:
C:\tools\nssm.exe install Syncthing "C:\Syncthing\syncthing.exe" --no-browser --home "C:\Syncthing\config" C:\tools\nssm.exe set Syncthing AppStdout C:\Syncthing\logs\syncthing.out.log C:\tools\nssm.exe set Syncthing AppStderr C:\Syncthing\logs\syncthing.err.log C:\tools\nssm.exe set Syncthing AppRotateFiles 1 C:\tools\nssm.exe set Syncthing AppRotateBytes 10485760 C:\tools\nssm.exe start Syncthing--no-browser是避免启动时弹出浏览器,--home指定配置目录,方便以后整体迁移配置。AppRotateBytes让日志单文件超过 10MB 自动轮转,防止日志把磁盘空间吃干净。服务运行身份建议用专门的账号,并确保该账号对同步目录有完整的读写权限;如果目录权限不足,会出现各种莫名其妙的同步失败,这部分排错成本很高。
4. 两台 Windows Server 首次配对与文件夹同步
4.1 初始化与 Web 管理界面
服务启动后,在服务器本地浏览器访问http://127.0.0.1:8384就能进入 Syncthing 管理界面。第一次进入会让设置 GUI 用户名和密码,这个认证只保护管理后台,别忘了配。生产服务器上如果远程管理,要把管理界面的监听地址从默认的 127.0.0.1 改成内网 IP 或 0.0.0.0,然后再访问http://内网IP:8384。
这里有个新手容易困惑的点:“Syncthing 账号密码”到底在哪设置?它并不是像网盘那样的登录账号体系,两台服务器之间靠设备 ID 互信,不需要密码。GUI 用户名密码只是后台管理的访问凭证,别把这两个概念混在一起。
4.2 交换设备 ID 完成双机互信
Syncthing 的信任逻辑很特别,每台设备有一串类似ABC1234-DEFG...的 ID,是 156 位的随机指纹。配对过程就是把对方的设备 ID 添加到自己的设备列表里。
具体操作:在 A 服务器的管理界面,点右下角“操作 → 显示设备 ID”,复制那一串长字符串。然后点“添加远程设备”,把 B 服务器的设备 ID 粘贴进去。Switch 到 B 服务器的管理界面,会收到一个设备添加请求,确认即可。反过来也可以直接在 B 上添加 A 的 ID。两端都把对方添加完之后,设备列表里会显示绿色已连接。
我建议给每台设备起一个明确的名字,比如“PROD-SRV-01”“BACKUP-SRV-02”,设备一多以后,在连接列表里一眼能分清谁是谁。这一步看似小事,真到排障的时候能省不少时间。
4.3 添加文件夹并选择同步方向
设备配对完成后,在任意一台服务器上“添加文件夹”,输入文件夹 ID 和路径,然后在“共享”标签页勾选另一台设备。这里最容易纠结的就是同步方向,我的建议如下:
如果是“主服务器 A → 备份服务器 B”的单向备份场景,在 A 上把文件夹类型设为“仅发送”,在 B 上把同一个文件夹设为“仅接收”。这样只有 A 的改动会推到 B,B 本地不会反向影响 A。
如果是两台服务器互备,分别开两个文件夹,各自文件夹方向对着对方反向即可。比如 A 的“业务数据”通过仅发送推到 B,B 的“内部文档”通过仅发送推到 A。两边都能拿到对方最新的文件,又不会互相覆盖。
此外在文件夹高级设置里有一个“忽略删除”的选项,打开后即使源端删除了文件,接收端也会把本地文件留着。对备份机来说,这个选项加上文件版本控制,相当于双重保险:一份保留在版本目录,一份直接保存在原地。代价是备份端会积累一些源端已不存在的文件,得留意磁盘占用。
4.4 第一轮全量同步的性能观察
首次同步是全量传输,传输速度主要看两台服务器之间的网络带宽。我在千兆内网同步几百 GB 数据时,速度能跑到几百 MB/s,过程很平稳。如果目录里是几百万个小文件,首次同步会明显变慢,因为每个文件都要做哈希计算和状态确认,这是正常现象,耐心等到同步完成即可。
在管理界面主页面,每个共享文件夹旁边都有状态,从“同步中”到“已同步”。点开远程设备详情,能看到实时传输速度和待同步数量。建议第一次全量同步放在业务低峰期执行,避免抢占业务带宽。首次同步完成后,后续的实时同步就是监听触发加块级增量,开销会小很多。
5. “后悔药”的核心:文件版本控制怎么配
5.1 版本控制的底层逻辑
版本控制的原理其实很简单:Syncthing 在应用远端更新或删除前,会先把本地当前版本的文件移动/复制到版本目录,备份这个名字带着时间戳的旧文件,然后再执行真正的覆盖或删除。这样同步操作本身不变,但被覆盖和删除的旧版本被“挽救”下来了。
这个思路类似数据库的归档日志,也像你打游戏时手动存的多个存档档位。你不需要的时候它们静默躺着,需要的时候,任何一个时间点都可能成为救命稻草。理解这一点很重要,因为它决定了“后悔药”不是把所有历史都无限堆积,而是有策略地保留一部分关键时间点的副本。
5.2 三种模式怎么选
Syncthing 的文件版本控制有三种内置模式,实际使用中我会这样区分:
| 模式 | 机制 | 典型场景 |
|---|---|---|
| Trash Can | 被覆盖/删除的文件转移到版本目录,可设置保留天数 | 只防误删,不关心版本个数 |
| Simple | 只保留最近 N 个版本 | 追求简单,磁盘空间有限 |
| Staggered | 按时间间隔保留不同阶段的版本,近期密集、历史稀疏 | 生产环境推荐默认选项 |
Trash Can 是“回收站”思路,给每个被删文件搬进版本目录,定个保留天数,到期清理。Simple 是“固定保留最近几版”,参数最小,适合目录不大、变化不频繁的机器。Staggered 最大的优势是空间利用率高:它能做到两小时前每分钟都有版本找回来、一天前每几小时一个版本、一个月前每天一个版本,相当于精细保留近期、粗略保留远期,用有限空间换最长回溯周期。
5.3 一个适合备份场景的配置建议
如果预算和磁盘空间都允许,我建议直接上 Staggered。在管理界面点文件夹 → 编辑 → 版本控制标签页,选择 Staggered,配置核心参数:
- 版本文件保留年龄:按你业务需要设置,常见 180 天
- 清理任务运行间隔:默认 3600 秒就可以,让清理任务每小时扫一次
- 自定义版本目录路径:填
D:\SyncVersion,这是最关键的一步
这里的一定要啰嗦一遍:版本目录尽量放到同步文件夹之外,宁可多占用一块独立磁盘,也不要放进同步目录内。原因我会在第 6 章勒索病毒场景里详细说,这里先记住结论。
如果磁盘空间紧张,可以用 Simple 模式,保留最近 10 个版本,基本能满足手工误操作的紧急回滚。等业务和磁盘都宽裕了,再切成 Staggered,不需要重建文件夹,切完立即生效。
5.4 误删除后的完整恢复流程
配置完成后,做一次真实的恢复演练非常必要。假设误删了D:\SyncData\config\app.json,此时同步已经把这个删除传到了带版本控制的备份机。恢复步骤:
- 在带版本控制的备份机管理界面,先暂停这个共享文件夹的同步
- 进入版本目录
D:\SyncVersion\config\,找到一个带有时间戳后缀的同名文件 - 按时间戳判断需要恢复到哪个时间点,把文件复制回原数据目录的
config路径 - 确认文件内容正确
- 在管理界面恢复文件夹同步,让恢复后的文件重新同步出去
恢复时暂停同步是很多人会忽略的细节。如果不暂停,你把历史版本复制回数据目录的瞬间,Syncthing 会把它当成一次新的本地修改立刻同步出去,同时版本目录又会因为这次复制生成一条新版本记录,现场会在短时间内变乱,所以先暂停、再恢复是唯一稳妥的操作顺序。
6. 运行半年后我总结的踩坑清单
6.1 小文件海量同步的性能优化
如果同步目录里堆着几十万个几 KB 的小文件,比如代码仓库、静态资源目录,问题就来了。文件监听每次触发后,Syncthing 都要做状态比对和哈希校验,文件一多,CPU 和内存占用会明显爬升。
我的处理方式是三层组合。第一,在文件夹设置里把扫描间隔从默认的 3600 秒调短到 60~300 秒,作为兜底;第二,确认“监视文件系统变化”处于开启状态,让实时触发和定期扫描双保险;第三,用.stignore文件排除那些根本不需要同步的目录,比如node_modules、临时目录、缩略图缓存。.stignore放在同步文件夹根目录,语法简单:
(?i)*.tmp (?i)*.temp (?i)node_modules (?i)Thumbs.db6.2 数据库文件被占用导致的同步停滞
这是 Windows Server 场景里几乎必踩的坑。SQL Server 的 mdf/ldf 文件在实例运行期间是被进程独占锁定的,Syncthing 去读取时直接 Access Denied,同步进度卡在那里反复重试。
我实际遇到时排查了很久,最后发现是同步了正在使用的数据库文件。这类文件即便这次侥幸读到了,也可能是非一致性的半个快照,同步到备份机没有实际意义。正确的做法是:在.stignore里排除数据库原始文件:
(?i)*.mdf (?i)*.ldf同步 SQL Server 定期生成的备份文件(.bak)才是有意义的。如果业务真的需要数据库实时容灾,请用 SQL Server 自身的可用性组或日志传送,而不是拿通用文件同步工具硬扛。这个边界要划清楚,任何工具都有它擅长的范围。
6.3 版本目录体积膨胀与清理策略
开了历史版本之后,日子久了版本目录会涨到让人肉疼。尤其那些大文件频繁修改的业务,比如几十 MB 的配置文件每半小时变一次,一天就是几十份旧版本,一个月就是几百 GB。
清理策略有两个层面。第一是信赖 Staggered 内置的清理任务,保证清理间隔和保留年龄都配好了;第二是人工兜底,自己写个 PowerShell 脚本定期清理超过 180 天的历史版本文件,放入计划任务:
$cutoff = (Get-Date).AddDays(-180) Get-ChildItem "D:\SyncVersion" -Recurse -File | Where-Object { $_.LastWriteTime -lt $cutoff } | Remove-Item -Force这类脚本跑之前先做好备份,确认目录路径没有写错,PowerShell 的真实删文件动作不经过回收站,路径错一个字母可能就误删了。脚本先加-WhatIf参数预览结果是我固定的习惯。
6.4 勒索病毒场景下历史版本的生死存亡
这是大家很关心的一个场景:如果生产服务器中了勒索病毒,文件被批量加密,Syncthing 会把加密后的文件实时同步到备份机,紧接着历史版本就成活教材了?得看版本目录放哪。
如果版本目录还放在同步文件夹内部,勒索病毒在遍历加密文件时会顺手把.stversions里的历史版本也一起加密,后悔药直接报废。所以第 5 章那个“版本目录放到同步文件夹之外”的建议,在这里就是关键防线。
如果确实发现服务器被加密,第一动作是立刻断开备份机的网络或暂停同步,阻止加密后的文件继续覆盖历史版本,然后从独立版本目录里按时间戳找回加密前的最后一份文件。额外还可以对版本目录再做逐日快照,比如 Windows 自带的卷影副本或者定期复制到其他介质,让后悔药再多一层保险。
6.5 监听失效:文件改了但没触发同步
Syncthing 的文件监听机制大部分场景很灵敏,但在某些情况下会失效。比如同步目录位于网络映射盘、部分虚拟磁盘、某些 SAN 挂载卷,或者文件数量已经大到监听事件被操作系统丢弃的程度。现象就是:你在源端改了文件,管理界面半天没有反应。
排查方法是先看管理界面的事件日志里有没有文件监听相关的错误信息。解决方向就是前面说的:把扫描间隔调短,保留定时全量扫描兜底。手动应急时,页面上也有“重新扫描全部”按钮,点了以后立刻触发一次全量状态比对,比干等监听可靠得多。这种场景充分说明了一个道理:再好的实时监听,也要留着定时扫描当保安,双保险才敢走开。
最后再分享一点个人的使用习惯。这套方案稳定跑起来之后,我最大的收获不是省了几台备份服务器的钱,而是终于敢在生产服务器上快速操作了。以前改一个重要配置之前,心里总要先过一遍“万一改坏了怎么回滚”,现在误删了文件、覆盖错了配置,我都能从容地回到几小时前、几天前甚至几个月前的状态。但前提是你真的把版本控制开到了同步文件夹之外,真的确认过删除动作会被历史版本兜住,而且真的做过一次完整的恢复演练。找个业务低峰期故意删一个测试文件,走一遍找回流程,把“后悔药”亲手吃一次,你才会真正信任这套方案。