15.4 可唤醒停机期间的工作任务

想像一个环境,你的 Linux 服务器有一个工作是需要在每周的星期天凌晨 2 点进行,但是很不巧的,星期六停电了~所以你得要星期一才能进公司去启动服务器。 那么请问,这个星期天的工作调度还要不要进行?因为你开机的时候已经是星期一,所以星期天的工作当然不会被进行,对吧!

问题是,若是该工作非常重要 (例如例行备份), 所以其实你还是希望在下个星期天之前的某天还是进行一下比较好~那你该怎办?自己手动执行?如果你跟鸟哥一样是个记忆力超差的家伙,那么肯定“记不起来某个重要工作要进行”的啦! 这时候就得要靠 anacron 这个指令的功能了!这家伙可以主动帮你进行时间到了但却没有执行的调度喔!

15.4.1 什么是 anacron

anacron 并不是用来取代 crontab 的,anacron 存在的目的就在于我们上头提到的,在处理非 24 小时一直启动的 Linux 系统的 crontab 的执行! 以及因为某些原因导致的超过时间而没有被执行的调度工作。

其实 anacron 也是每个小时被 crond 执行一次,然后 anacron 再去检测相关的调度任务有没有被执行,如果有超过期限的工作在, 就执行该调度任务,执行完毕或无须执行任何调度时,anacron 就停止了。

由于 anacron 默认会以一天、七天、一个月为期去侦测系统未进行的 crontab 任务,因此对于某些特殊的使用环境非常有帮助。 举例来说,如果你的 Linux 主机是放在公司给同仁使用的,因为周末假日大家都不在所以也没有必要打开, 因此你的 Linux 是周末都会关机两天的。但是 crontab 大多在每天的凌晨以及周日的早上进行各项任务, 偏偏你又关机了,此时系统很多 crontab 的任务就无法进行。 anacron 刚好可以解决这个问题!

那么 anacron 又是怎么知道我们的系统啥时关机的呢?这就得要使用 anacron 读取的时间记录文件 (timestamps) 了! anacron 会去分析现在的时间与时间记录文件所记载的上次执行 anacron 的时间,两者比较后若发现有差异, 那就是在某些时刻没有进行 crontab 啰!此时 anacron 就会开始执行未进行的 crontab 任务了!

15.4.2 anacron 与 /etc/anacrontab

anacron 其实是一支程序并非一个服务!这支程序在 CentOS 当中已经进入 crontab 的调度喔!同时 anacron 会每个小时被主动执行一次喔! 咦!每个小时?所以 anacron 的配置文件应该放置在 /etc/cron.hourly 吗?嘿嘿!您真内行~赶紧来瞧一瞧:

[root@study ~]# cat /etc/cron.hourly/0anacron
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
    day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
    exit 0;
fi
# 上面的语法在检验前一次执行 anacron 时的时间戳记!

# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
    /usr/bin/on_ac_power >/dev/null 2>&1
    if test $? -eq 1; then
    exit 0
    fi
fi
/usr/sbin/anacron -s
# 所以其实也仅是执行 anacron -s 的指令!因此我们得来谈谈这支程序!

基本上, anacron 的语法如下:

[root@study ~]# anacron [-sfn] [job]..
[root@study ~]# anacron -u [job]..
选项与参数:
-s  :开始一连续的执行各项工作 (job),会依据时间记录文件的数据判断是否进行;
-f  :强制进行,而不去判断时间记录文件的时间戳记;
-n  :立刻进行未进行的任务,而不延迟 (delay) 等待时间;
-u  :仅更新时间记录文件的时间戳记,不进行任何工作。
job :由 /etc/anacrontab 定义的各项工作名称。

在我们的 CentOS 中,anacron 的进行其实是在每个小时都会被抓出来执行一次, 但是为了担心 anacron 误判时间参数,因此 /etc/cron.hourly/ 里面的 anacron 才会在文件名之前加个 0 (0anacron),让 anacron 最先进行!就是为了让时间戳记先更新!以避免 anacron 误判 crontab 尚未进行任何工作的意思。

接下来我们看一下 anacron 的配置文件: /etc/anacrontab 的内容好了:

[root@study ~]# cat /etc/anacrontab
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
RANDOM_DELAY=45           # 随机给予最大延迟时间,单位是分钟
START_HOURS_RANGE=3-22    # 延迟多少个小时内应该要执行的任务时间

1         5        cron.daily         nice run-parts /etc/cron.daily
7        25        cron.weekly        nice run-parts /etc/cron.weekly
@monthly 45        cron.monthly       nice run-parts /etc/cron.monthly
天数     延迟时间  工作名称定义       实际要进行的指令串
# 天数单位为天;延迟时间单位为分钟;工作名称定义可自订,指令串则通常与 crontab 的设置相同!

[root@study ~]# more /var/spool/anacron/*
::::::::::::::
/var/spool/anacron/cron.daily
::::::::::::::
20150731
::::::::::::::
/var/spool/anacron/cron.monthly
::::::::::::::
20150703
::::::::::::::
/var/spool/anacron/cron.weekly
::::::::::::::
20150727
# 上面则是三个工作名称的时间记录文件以及记录的时间戳记

我们拿 /etc/cron.daily/ 那一行的设置来说明好了。那四个字段的意义分别是:

  • 天数:anacron 执行当下与时间戳记 (/var/spool/anacron/ 内的时间纪录档) 相差的天数,若超过此天数,就准备开始执行,若没有超过此天数,则不予执行后续的指令。
  • 延迟时间:若确定超过天数导致要执行调度工作了,那么请延迟执行的时间,因为担心立即启动会有其他资源冲突的问题吧!
  • 工作名称定义:这个没啥意义,就只是会在 /var/log/cron 里头记载该项任务的名称这样!通常与后续的目录资源名称相同即可。
  • 实际要进行的指令串:有没有跟 0hourly 很像啊!没错!相同的作法啊!通过 run-parts 来处理的!

根据上面的配置文件内容,我们大概知道 anacron 的执行流程应该是这样的 (以 cron.daily 为例):

  1. 由 /etc/anacrontab 分析到 cron.daily 这项工作名称的天数为 1 天;
  2. 由 /var/spool/anacron/cron.daily 取出最近一次执行 anacron 的时间戳记;
  3. 由上个步骤与目前的时间比较,若差异天数为 1 天以上 (含 1 天),就准备进行指令;
  4. 若准备进行指令,根据 /etc/anacrontab 的设置,将延迟 5 分钟 + 3 小时 (看 START_HOURS_RANGE 的设置);
  5. 延迟时间过后,开始执行后续指令,亦即“ run-parts /etc/cron.daily ”这串指令;
  6. 执行完毕后, anacron 程序结束。

如此一来,放置在 /etc/cron.daily/ 内的任务就会在一天后一定会被执行的!因为 anacron 是每个小时被执行一次嘛! 所以,现在你知道为什么隔了一阵子才将 CentOS 开机,开机过后约 1 小时左右系统会有一小段时间的忙碌!而且硬盘会跑个不停!那就是因为 anacron 正在执行过去 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 里头的未进行的各项工作调度啦!这样对 anacron 有没有概念了呢? ^_^

最后,我们来总结一下本章谈到的许多配置文件与目录的关系吧!这样我们才能了解 crond 与 anacron 的关系:

  1. crond 会主动去读取 /etc/crontab, /var/spool/cron/, /etc/cron.d/ 等配置文件,并依据“分、时、日、月、周”的时间设置去各项工作调度;
  2. 根据 /etc/cron.d/0hourly 的设置,主动去 /etc/cron.hourly/ 目录下,执行所有在该目录下的可执行文件;
  3. 因为 /etc/cron.hourly/0anacron 这个指令档的缘故,主动的每小时执行 anacron ,并调用 /etc/anacrontab 的配置文件;
  4. 根据 /etc/anacrontab 的设置,依据每天、每周、每月去分析 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 内的可执行文件,以进行固定周期需要执行的指令。

也就是说,如果你每个周日的需要执行的动作是放置于 /etc/crontab 的话,那么该动作只要过期了就过期了,并不会被抓回来重新执行。但如果是放置在 /etc/cron.weekly/ 目录下,那么该工作就会定期,几乎一定会在一周内执行一次~如果你关机超过一周,那么一开机后的数个小时内,该工作就会主动的被执行喔! 真的吗?对啦!因为 /etc/anacrontab 的定义啦!

鸟哥的图示

Tips 基本上,crontab 与 at 都是“定时”去执行,过了时间就过了!不会重新来一遍~那 anacron 则是“定期”去执行,某一段周期的执行~ 因此,两者可以并行,并不会互相冲突啦!