我的服务器在午夜运行许多 cron 作业。每个作业都会创建一个备份,通过创建一个 tarball 并使用xz
.
由于xz
是 CPU 和内存猪,我为每个作业添加了随机延迟,因此它们“不应该”相互破坏。但是有时确实会发生这种情况,并且会给服务器带来沉重的负担。
假设:
- 根据我的流量,午夜是进行备份的最佳时间 - 但仍然有流量(这就是我想避免过度负载的原因)
- 每个面向公众的应用程序都与它自己的备份作业相关联,并且它们是解耦的(它们彼此不知道) - 所以我不能将备份 cron 作业合并到一个作业中,因为我需要那种粒度
- 我不能硬编码每个人的开始时间,因为这会增加维护 - 将应用程序添加到服务器(通过 ansible),我只需部署它并将备份 cron 作业(计划在午夜)放入
/etc/cron.d/
,然后随机工作开始前的延迟通常就足够了 - 我稍微限制了作业
tar ... | pv --rate-limit ... | xz ...
- 但是虽然这减少了每个作业的负载,但它也减慢了每个作业的速度,因此增加了多个作业同时运行的可能性(当它们加在一起时可能会占用 100% 的 CPU)
一个可能的解决方案是为每个作业创建一个临时文件,表明它正忙,然后将其删除。问题是如果一个作业检测到这个文件,它会做什么?睡觉?多长时间?我可以使用 让它随机休眠一段时间at
,但是如果我的备份脚本出现问题,我可能会有大量的作业相互竞争。另一个维护难题。
那么,通常如何解决这个问题呢?基本上,这是一种安排相关 cron 作业的简单方法,不会让它们相互干扰,也不需要微调开始时间。
使用shell 操作符,例如,在午夜运行
command1
,command2
不管前者的输出如何,使用:或者,您可以
command2
仅在command1
成功完成后运行(返回退出状态为零):command1
当 的失败可能表示排除 的成功的潜在错误时,后者可能更有用command2
。随机分配开始时间有利于避免高峰时间,并且使用 Ansible 很容易做到。但并不能真正确保资源可用于维持多个并发压缩作业。关于如何进行低影响备份的方法有几种,请考虑其中的一些或全部。
通过基于 CPU 节流的程序运行您的命令列表。例如,GNU 并行
--limit 100%
只会在平均负载低于 CPU 数量时运行。每个作业都尝试获取少量锁中的一个。例如
flock
来自 util-linux、Python 或 Perl。看起来很简单,但是维护其中的一些会很烦人。我认为具有内置作业管理的包装器命令更健壮,例如 GNU 并行。评估您的压缩算法。zstd是现代且快速的,只需要更多的内存。
将备份作业分散到更多小时。考虑一下 00:00 到 03:00 是否可以满足您的性能和备份要求。
添加 CPU。为峰值容量调整大小可能很昂贵,但它允许更多的压缩线程。
将备份完全卸载到另一台主机。拍摄存储阵列或基于云的磁盘快照。呈现给不同的主持人。从那里备份。
查看@JohnMahowald 的答案以获得出色的选项列表,包括巧妙地处理争用。
我决定做的不是将备份作业添加到
/etc/cron.d
,而是将它们添加到自定义 cron 目录,例如/etc/cron.backupjobs/
.然后我将添加一个“主”作业,按顺序
/etc/cron.d/
运行作业。/etc/cron.backupjobs/