我有一个设置,其中通过 SSH 连接使用 Unison 在两个 Linux 服务器之间同步文件。这是通过 cron 运行以下命令来实现的:
unison -auto -batch PROFILE
文件集的更改几乎只发生在一侧(另一个系统是异地副本)。它们大多是通过与客户端计算机的另一个 Unison 同步运行(手动触发)进行的,并且间隔时间可能从几个小时到几周不等。因此,两台机器之间的冲突在实践中并不是什么大问题,并且更改传播到另一端的最多 24 小时的延迟是可以接受的。
我将 Unison 作为 cron 作业而不是-repeat
(大概作为 systemd 服务)运行的原因是:
- 可预测的同步时间,因为 cron 作业被安排在我不期望第三台机器进行任何手动同步操作的时间(而,比如说,
-repeat 86400
会随着同步操作的持续时间而漂移)。 - 更改主要发生在服务器 A 上,而服务器到服务器同步作业由服务器 B 触发(如果服务器 B 发起连接,网络方面是否更容易)。因此,据我了解,
-repeat watch
不会接受大部分更改,即使使用-repeat watch+TIME
,我也几乎完全依赖TIME
(如果我错过了某些内容,请纠正我)。
当变化确实发生时,变化的幅度通常很小。然而,有时,要传输的数据量使得单个 Unison 运行的持续时间是两个 Unison cron 作业之间的间隔的数倍(系统之间的带宽受到一定限制)。这意味着当 cron 在同一组文件上启动下一个进程时,一个 Unison 进程仍在运行。
我认为 Unison 具有锁定机制,这大概可以防止“新”进程干扰“旧”进程正在处理的任何事情(但如果我拧干或遗漏了某些东西,请纠正我)。但我想知道在这种情况下第二个 Unison 进程会做什么 - 我观察到它不会退出而是保留下来。这是否意味着第二个进程将等待第一个进程完成,然后才开始同步(这样将仅包括在第一次同步进行时更改的文件,因此在第一次运行时无法同步)?
当另一个 Unison 进程仍在同一配置文件上运行时启动第二个 Unison 进程是否安全? (如果不是,当且仅当两个并发 Unison 实例存在相互干扰的风险时,建议采用什么方法来阻止它们?)
unison -repeat wait+TIME
与偶尔有多个 Unison 实例排队、一个正在运行而其他等待其完成的资源开销又如何呢?
如果您想避免在另一个进程已经运行时启动第二个 unison 实例,您可以通过命令使用锁定文件来控制启动
flock
。这是一个通用解决方案,它适用于“当另一个实例已经运行时防止第二个实例运行”。如果您希望在另一个实例运行时启动失败:
如果您希望启动阻塞直到现有进程退出:
请参阅
flock(1)
手册页以获取更多信息。Unison(版本 2.51.2)创建自己的锁定文件。刚刚测试它,从命令行运行一致同步两次,第二次是在第一个仍在运行时,我得到了这个错误(带有匿名的内容):
因此,如果第二个 unison 实例检测到这些锁定文件并推测当前正在运行另一个 unison 同步,那么它似乎将致命退出。
我实际上建议 systemd 非常适合您想要“cron 但单一实例”的情况。您不需要将其保留为长期运行的服务 - 您可以以类似 cron 的方式使用 systemd 计时器,同时利用 systemd 来管理实例。
Type=exec
。在进程退出之前,该服务将被视为活动的。使用当前与 cron 相同的命令行。OnCalendar=
) 或一段时间后发生(OnUnitActiveSec=
相对于上次服务启动时间,OnUnitInactiveSec=
相对于上次服务停止时间)。就我个人而言,我喜欢日历,因为它更可预测并且不会漂移。以 SOMEUSER 身份使用配置文件 SOMEPROFILE 运行 Unison 的示例单元文件(除了它们的
.service
和.timer
后缀外,两个单元文件必须具有相同的名称):unison.service
:unison.timer
(每天 13:37 触发;有关OnCalendar
语法man 5 systemd.time
,请参阅日历事件部分):将这两个单元文件放入
/etc/systemd/system/
,然后运行:您可以通过运行来测试设置
sudo systemctl start unison.service
- 这仅需要服务单元,而不需要计时器单元。这也是一种不按计划开始同步的方法。 Unison 输出将unison
作为标签写入系统日志。我还在
flock
cron 作业 shell 脚本中使用以避免一次运行多个任务。我使用的方法与之前答案中建议的方法不同。我将展示代码并描述其优点/缺点。Bash 代码片段,只需稍作更改即可在其他 shell 中使用:
缺点:
好处:
fuser /path/to/lock.file
)文件描述符 300 并不特殊,它只是一个高编号描述符,不太可能被脚本的其他部分使用。
与其他一切一样,这是您想要的行为和您不想要的行为之间的权衡。