systemd timer 怎么用 RandomizedDelaySec 错峰执行
来源:17golang原创
时间:2026-10-05 05:24:48 243浏览 收藏
RandomizedDelaySec= 的作用,是在 systemd timer 算出的基准触发时间之后,再增加一段均匀分布的随机延迟。比如每天 02:00 运行的任务配置 RandomizedDelaySec=30min,实际触发会落在 02:00 到 02:30 之间,从而减少多台机器同时访问数据库、对象存储或更新服务器造成的瞬时压力。
官方文档:https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html
OnCalendar=或其他定时条件负责确定基准时刻,RandomizedDelaySec=只在其上增加随机延迟。- 随机值默认在每次触发前重新选择;需要每台机器保持固定偏移时,再启用
FixedRandomDelay=true。 AccuracySec=允许 systemd 合并附近的定时事件,它与随机延迟解决的是不同问题。
前置条件:先确认版本与任务边界
RandomizedDelaySec= 从 systemd 229 起可用,FixedRandomDelay= 从 systemd 247 起可用。先查看系统版本和 timer 手册,避免在较旧发行版上直接套用后文的扩展配置。
# 查看当前 systemd 版本,并确认 timer 手册包含目标参数
systemd --version
man systemd.timer
这个实验假设要每天执行一次缓存预热脚本。脚本本身应当可重复执行,并能在多个实例偶尔重叠时保持安全。随机延迟只降低碰撞概率,不提供分布式锁,也不保证不同主机绝对不会在同一秒触发。
步骤一:创建一次性 service unit
timer 负责决定何时激活,真正的命令放在同名 service 中。创建 /etc/systemd/system/cache-warmup.service:
# /etc/systemd/system/cache-warmup.service
[Unit]
Description=预热应用缓存
[Service]
Type=oneshot
# 使用固定绝对路径,避免依赖交互式 Shell 的 PATH。
ExecStart=/usr/local/sbin/cache-warmup
Type=oneshot 适合运行完成后退出的批处理任务。文件名为 cache-warmup.service,后面创建同名 cache-warmup.timer 后,timer 默认就会激活这个 service,不需要额外写 Unit=。
步骤二:先确定没有随机化的基准计划
先把基准计划写清楚,再设置错峰窗口。下面的日历表达式表示每天 02:00:00。可以用 systemd-analyze calendar 检查表达式解析结果,这一步只验证日历条件,不会展示最终随机偏移。
# 检查 OnCalendar 表达式会匹配哪些基准时刻
systemd-analyze calendar '*-*-* 02:00:00'
如果每台机器的基准时刻不同,就很难判断随机窗口到底覆盖哪里。保持统一的 OnCalendar=,再用 RandomizedDelaySec= 分散实际触发,配置更容易审计。
步骤三:在 timer 中加入随机延迟窗口
创建 /etc/systemd/system/cache-warmup.timer。以下配置把每日 02:00 作为基准,并把每次执行随机推迟 0 到 30 分钟:
# /etc/systemd/system/cache-warmup.timer
[Unit]
Description=每天错峰执行缓存预热
[Timer]
# 每天 02:00 是基准时刻,实际执行会在此后随机延迟。
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=30min
# 缩小事件合并窗口,让 30 分钟随机范围真正用于分散触发。
AccuracySec=1s
# 关机期间错过计划时,启动后补一次任务。
Persistent=true
[Install]
WantedBy=timers.target
官方文档说明,RandomizedDelaySec= 默认是 0,也就是不增加随机延迟。随机值会加在“下一次基准触发时间”和“服务管理器启动时间”两者中较晚的那个时间点上。对于普通日历 timer,可以把它理解为:先得到计划时刻,再向后推迟最多 30 分钟。

AccuracySec= 不是另一个随机窗口。它允许 systemd 把邻近的 timer 事件合并,以减少系统唤醒次数;RandomizedDelaySec= 则用于主动拉开相似 timer 的触发时间。官方建议在希望最大化分散效果时把 AccuracySec= 设得很小。这里采用 1 秒,已经适合多数分钟级错峰任务;若需要严格遵循最小合并窗口,可以按官方建议评估 1us。
步骤四:重新加载并启用 timer
写入两个 unit 后,让 systemd 重新读取配置,并同时启用、启动 timer:
# 重新加载 unit 文件,然后立即启动并设置为开机启用
sudo systemctl daemon-reload
sudo systemctl enable --now cache-warmup.timer
enable --now 同时完成两个动作:创建开机启用所需的链接,并在当前系统中启动 timer。只运行 enable 不等于当前立即开始等待;只运行 start 也不会自动获得下次开机启用状态。
步骤五:检查下一次触发时间与参数
启用后先看 timer 列表中的 NEXT 字段,再用 systemctl show 查看底层属性。list-timers 展示的是 systemd 已计算的下一次触发时间,因此它已经包含本轮随机延迟和精度处理的结果。
# 查看下一次实际触发时间,并核对随机延迟相关属性
systemctl list-timers cache-warmup.timer
systemctl show cache-warmup.timer \
-p NextElapseUSecRealtime \
-p RandomizedDelayUSec \
-p AccuracyUSec \
-p FixedRandomDelay
unit 文件里的高层配置名通常以 Sec 结尾,而 systemctl show 暴露的底层 D-Bus 属性常以 USec 结尾。两者表达同一个设置,只是底层属性使用微秒单位。若 NEXT 不在预期范围,优先检查 OnCalendar= 是否写对、旧 drop-in 是否覆盖配置,以及 timer 是否已经重新加载。
任务触发后,用 service 日志确认脚本是否成功执行:
# 查看本次和历史执行日志,失败时保留完整上下文
journalctl -u cache-warmup.service --since today
systemctl status cache-warmup.service
扩展实验:需要稳定错峰时启用 FixedRandomDelay
默认情况下,timer 每次迭代都会重新选择随机延迟。若希望同一台机器上的同一个 timer 总是保持稳定偏移,可以加入 FixedRandomDelay=true:
# /etc/systemd/system/cache-warmup.timer.d/stable-offset.conf
[Timer]
# 在 RandomizedDelaySec 窗口内,为该主机和 unit 保持稳定偏移。
FixedRandomDelay=true
这个固定值由 machine ID、服务管理器的用户标识以及 timer unit 名称共同派生。它只在 RandomizedDelaySec 不为 0 时生效。对批量部署的服务器而言,各主机通常会得到不同偏移,而单机自己的触发抖动会更小。

启用 drop-in 后仍需重新加载并重启 timer,才能重新计算等待状态:
# 应用 drop-in,并让 timer 使用新的固定随机策略
sudo systemctl daemon-reload
sudo systemctl restart cache-warmup.timer
systemctl list-timers cache-warmup.timer
Persistent、AccuracySec 与随机延迟怎么配合
| 参数 | 解决的问题 | 推荐判断 |
|---|---|---|
OnCalendar= | 定义基准计划 | 先用 systemd-analyze calendar 验证 |
RandomizedDelaySec=30min | 把相似任务分散到一个窗口 | 窗口应小于业务允许的最晚完成时间 |
AccuracySec=1s | 控制 systemd 合并 timer 事件的范围 | 强调错峰时设小,强调省电时可保留较大值 |
FixedRandomDelay=true | 让同一 timer 的随机偏移保持稳定 | 批量主机希望固定分片时启用 |
Persistent=true | 机器关机期间错过日历任务后补跑 | 任务允许开机后补执行时启用 |
Persistent=true 可能让多台刚开机的机器都产生补跑需求,而随机延迟可以继续降低它们同时启动任务的概率。但它仍不是集中式协调器:如果任务对并发有硬限制,还应在服务端设置队列、租约或互斥机制。
清理实验 unit
不再需要该实验时,先停用 timer,再删除 unit 和 drop-in,最后重新加载 systemd。不要只删除文件却留下仍在内存中等待的 timer。
# 停止并取消开机启用,然后移除本次实验配置
sudo systemctl disable --now cache-warmup.timer
sudo rm /etc/systemd/system/cache-warmup.timer
sudo rm /etc/systemd/system/cache-warmup.service
sudo rm -rf /etc/systemd/system/cache-warmup.timer.d
sudo systemctl daemon-reload
相关问题
RandomizedDelaySec 会提前执行任务吗?
不会。它是在已确定的基准触发时间之后增加非负随机延迟,不会把任务提前到 OnCalendar 之前。
为什么多台主机仍可能同时执行?
各 timer 独立选择随机值,不存在跨主机协调,因此只能降低碰撞概率,不能保证完全不重合。窗口太小或主机数量很多时,仍应使用服务端限流或分布式锁。
为什么修改 timer 后 NEXT 没变化?
先执行 systemctl daemon-reload,再重启 timer。还要用 systemctl cat cache-warmup.timer 检查发行版自带 unit 或旧 drop-in 是否覆盖了当前配置。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
132 收藏
-
395 收藏
-
231 收藏
-
470 收藏
-
306 收藏
-
362 收藏
-
467 收藏
-
485 收藏
-
文章 · linux | 21小时前 | Linux · Linux systemd-journald journald.conf RateLimitIntervalSec RateLimitBurst 日志限速208 收藏
-
466 收藏
-
239 收藏
-
文章 · linux | 1天前 | 定时任务 · Linux · 运维 · Cron OnCalendar Persistent systemd timer systemd-analyze calendar364 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习