企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## 17.4 systemctl 针对 timer 的配置文件 有时候,某些服务你想要定期执行,或者是开机后执行,或者是什么服务启动多久后执行等等的。在过去,我们大概都是使用 crond 这个服务来定期处理, 不过,既然现在有一直常驻在内存当中的 systemd 这个好用的东西,加上这 systemd 有个协力服务,名为 timers.target 的家伙,这家伙可以协助定期处理各种任务! 那么,除了 crond 之外,如何使用 systemd 内置的 time 来处理各种任务呢?这就是本小节的重点啰! * systemd.timer 的优势 在 archlinux 的官网 wiki 上面有提到,为啥要使用 systemd.timer 呢? * 由于所有的 systemd 的服务产生的信息都会被纪录 (log),因此比 crond 在 debug 上面要更清楚方便的多; * 各项 timer 的工作可以跟 systemd 的服务相结合; * 各项 timer 的工作可以跟 control group (cgroup,用来取代 /etc/secure/limit.conf 的功能) 结合,来限制该工作的资源利用 虽然还是有些弱点啦~例如 systemd 的 timer 并没有 email 通知的功能 (除非自己写一个),也没有类似 anacron 的一段时间内的随机取样功能 (random_delay), 不过,总体来说,还是挺不错的!此外,相对于 crond 最小的单位到分, systemd 是可以到秒甚至是毫秒的单位哩!相当有趣! * 任务需求 基本上,想要使用 systemd 的 timer 功能,你必须要有几个要件: * 系统的 timer.target 一定要启动 * 要有个 sname.service 的服务存在 (sname 是你自己指定的名称) * 要有个 sname.timer 的时间启动服务存在 满足上面的需求就 OK 了!有没有什么案例可以来实作看看?这样说好了,我们上个小节不是才自己做了个 backup.service 的服务吗?那么能不能将这个 backup.service 用在定期执行上面呢?好啊!那就来测试看看! * sname.timer 的设置值 你可以到 /etc/systemd/system 下面去创建这个 *.timer 档,那这个文件的内容要项有哪些东西呢?基本设置主要有下面这些: (man systemd.timer & man systemd.time) | [Timer] 部份 | | --- | --- | | 设置参数 | 参数意义说明 | | OnActiveSec | 当 timers.target 启动多久之后才执行这只 unit | | OnBootSec | 当开机完成后多久之后才执行 | | OnStartupSec | 当 systemd 第一次启动之后过多久才执行 | | OnUnitActiveSec | 这个 timer 配置文件所管理的那个 unit 服务在最后一次启动后,隔多久后再执行一次的意思 | | OnUnitInactiveSec | 这个 timer 配置文件所管理的那个 unit 服务在最后一次停止后,隔多久再执行一次的意思。 | | OnCalendar | 使用实际时间 (非循环时间) 的方式来启动服务的意思!至于时间的格式后续再来谈。 | | Unit | 一般来说不太需要设置,因此如同上面刚刚提到的,基本上我们设置都是 sname.server + sname.timer,那如果你的 sname 并不相同时,那在 .timer 的文件中, 就得要指定是哪一个 service unit 啰! | | Persistent | 当使用 OnCalendar 的设置时,指定该功能要不要持续进行的意思。通常是设置为 yes ,比较能够满足类似 anacron 的功能喔! | 基本的项目仅有这些而已,在设置上其实并不困难啦! * 使用于 OnCalendar 的时间 如果你想要从 crontab 转成这个 timer 功能的话,那么对于时间设置的格式就得要了解了解~基本上的格式如下所示: ``` 语法:英文周名 YYYY-MM-DD HH:MM:SS 范例:Thu 2015-08-13 13:40:00 ``` 上面谈的是基本的语法,你也可以直接使用间隔时间来处理!常用的间隔时间单位有: * us 或 usec:微秒 (10-6 秒) * ms 或 msec:毫秒 (10-3 秒) * s, sec, second, seconds * m, min, minute, minutes * h, hr, hour, hours * d, day, days * w, week, weeks * month, months * y, year, years 常见的使用范例有: ``` 隔 3 小时: 3h 或 3hr 或 3hours 隔 300 分钟过 10 秒: 10s 300m 隔 5 天又 100 分钟: 100m 5day # 通常英文的写法,小单位写前面,大单位写后面~所以先秒、再分、再小时、再天数等~ ``` 此外,你也可以使用英文常用的口语化日期代表,例如 today, tomorrow 等!假设今天是 2015-08-13 13:50:00 的话,那么: | 英文口语 | 实际的时间格式代表 | | --- | --- | | now | Thu 2015-08-13 13:50:00 | | today | Thu 2015-08-13 00:00:00 | | tomorrow | Thu 2015-08-14 00:00:00 | | hourly | *-*-* *:00:00 | | daily | *-*-* 00:00:00 | | weekly | Mon *-*-* 00:00:00 | | monthly | *-*-01 00:00:00 | | +3h10m | Thu 2015-08-13 17:00:00 | | 2015-08-16 | Sun 2015-08-16 00:00:00 | * 一个循环时间运行的案例 现在假设这样: * 开机后 2 小时开始执行一次这个 backup.service * 自从第一次执行后,未来我每两天要执行一次 backup.service 好了,那么应该如何处理这个脚本呢?可以这样做喔! ``` [root@study ~]# vim /etc/systemd/system/backup.timer [Unit] Description=backup my server timer [Timer] OnBootSec=2hrs OnUnitActiveSec=2days [Install] WantedBy=multi-user.target # 只要这样设置就够了!储存离开吧! [root@study ~]# systemctl daemon-reload [root@study ~]# systemctl enable backup.timer [root@study ~]# systemctl restart backup.timer [root@study ~]# systemctl list-unit-files | grep backup backup.service disabled # 这个不需要启动!只要 enable backup.timer 即可! backup.timer enabled [root@study ~]# systemctl show timers.target ConditionTimestamp=Thu 2015-08-13 14:31:11 CST # timer 这个 unit 启动的时间! [root@study ~]# systemctl show backup.service ExecMainExitTimestamp=Thu 2015-08-13 14:50:19 CST # backup.service 上次执行的时间 [root@study ~]# systemctl show backup.timer NextElapseUSecMonotonic=2d 19min 11.540653s # 下一次执行距离 timers.target 的时间 ``` 如上表所示,我上次执行 backup.service 的时间是在 2015-08-13 14:50 ,由于设置两个小时执行一次,因此下次应该是 2015-08-15 14:50 执行才对! 由于 timer 是由 timers.target 这个 unit 所管理的,而这个 timers.target 的启动时间是在 2015-08-13 14:31 , 要注意,最终 backup.timer 所纪录的下次执行时间,其实是与 timers.target 所纪录的时间差!因此是“ 2015-08-15 14:50 - 2015-08-13 14:31 ”才对! 所以时间差就是 2d 19min 啰! * 一个固定日期运行的案例 上面的案例是固定周期运行一次,那如果我希望不管上面如何运行了,我都希望星期天凌晨 2 点运行这个备份程序一遍呢?请注意,因为已经存在 backup.timer 了! 所以,这里我用 backup2.timer 来做区隔喔! ``` [root@study ~]# vim /etc/systemd/system/backup2.timer [Unit] Description=backup my server timer2 [Timer] OnCalendar=Sun *-*-* 02:00:00 Persistent=true Unit=backup.service [Install] WantedBy=multi-user.target [root@study ~]# systemctl daemon-reload [root@study ~]# systemctl enable backup2.timer [root@study ~]# systemctl start backup2.timer [root@study ~]# systemctl show backup2.timer NextElapseUSecRealtime=45y 7month 1w 6d 10h 30min ``` 与循环时间运行差异比较大的地方,在于这个 OnCalendar 的方法对照的时间并不是 times.target 的启动时间,而是 Unix 标准时间! 亦即是 1970-01-01 00:00:00 去比较的!因此,当你看到最后出现的 NextElapseUSecRealtime 时,哇!下一次执行还要 45 年 + 7 个月 + 1 周 + 6 天 + 10 小时过 30 分~刚看到的时候,鸟哥确实因此揉了揉眼睛~确定没有看错...这才了解原来比对的是“日历时间”而不是某个 unit 的启动时间啊!呵呵! 通过这样的方式,你就可以使用 systemd 的 timer 来制作属于你的时程规划服务啰!