初识Linux(十二)------ 计划任务(crontab)

  系统常常会主动的进行一些任务,这些任务到底是谁在设置工作的? 如果你想要让自己设计的备份程序可以自动的在系统下面执行,而不需要手动来启动他,又该如何处置? 这些例行的工作可能又分为“单一”工作与“循环”工作,在系统内又是哪些服务在负责? 还有还有,如果你想要每年生日前一天就发出一封信件提醒自己不要忘记,可以办的到吗?

1. 计划任务

  Linux 通过 crontab 和 at 来进行计划任务调度。

1.1 Linux 计划任务的种类: at, cron

  日常中,一般是两种计划的方式:

  • 一种是例行性的,就是每隔一定的周期要来办的事项;
  • 一种是突发性的,就是这次做完以后就没有的那一种。

   Linux 下使用 at 与 crontab 来达到这种功能。

  • at :at 是个可以处理仅执行一次就结束调度的指令,不过要执行 at 时, 必须要有 atd 这个服务的支持才行。在某些新版的 distributions 中,atd 可能默认并没有启动,那么 at 这个指令就会失效,不过CentOS 默认是启动的。
  • crontab :crontab 这个指令所设置的工作将会循环的一直进行下去。可循环的时间为分钟、小时、每周、每月或每年等。crontab 除了可以使用指令执行外,亦可编辑 /etc/crontab 来支持。 至于让 crontab 可以生效的服务则是 crond 这个服务。

  下面我们先来谈一谈 Linux 的系统到底在做什么事情,怎么有若干多的工作调度在进行,然后再回来谈一谈 at 与 crontab。

1.2 CentOS Linux 系统上常见的例行性工作

  如果你使用过 Linux ,那么你大概会发现到 Linux 会主动的帮我们进行一些工作。比方说自动的进行线上更新 (on-line update)、自动的进行 updatedb ( locate 指令) 更新文件名数据库、自动的作登录文件分析 (所以 root 常常会收到标题为 logwatch 的信件) 等等。这是由于系统要正常运行的话, 某些在背景下面的工作必须要定时进行的缘故。基本上 Linux 系统常见的例行性任务有:

  • 进行日志文件的轮替 (log rotate)

  Linux 会主动的将系统所发生的各种信息都记录下来,这就是日志文件。 由于系统会一直记录登录信息,所以日志文件将会越来越大!我们知道大型文件不但占容量还会造成读写性能的困扰, 因此适时的将登录文件数据挪一挪,让旧的数据与新的数据分别存放,则比较可以有效的记录登录信息。这就是 log rotate 的任务,这也是系统必要的例行任务;

  • 日志文件分析 logwatch 的任务

  如果系统发生了软件问题、硬件错误、信息安全问题等,绝大部分的错误信息都会被记录到日志文件中, 因此系统管理员的重要任务之一就是分析日志文件。但你不可能手动通过 vim 等软件去查看日志文件,因为数据太复杂了! 我们的 CentOS 提供了一只程序“ logwatch ”来主动分析登录信息,所以你会发现,你的 root 老是会收到标题为 logwatch 的信件,那是正常的。

  • 创建 locate 的数据库

  在之前介绍 locate 指令时, 我们知道该指令是通过已经存在的文件名数据库来进行系统上文件名的查询。我们的文件名数据库是放置到 /var/lib/mlocate/ 中。 这个数据库会自动更新,系统会主动的进行 updatedb。

  • man page 查询数据库的创建

  与 locate 数据库类似的,可提供快速查询的 man page db 也是个数据库,但如果要使用 man page 数据库时,就得要执行 mandb 才能够创建,而这个 man page 数据库也是通过系统的计划任务调度来自动执行的。

  • RPM 软件日志文件的创建

  RPM是一种软件管理的机制。由于系统可能会常常变更软件, 包括软件的新安装、非经常性更新等,都会造成软件文件名的差异。为了方便未来追踪,系统也帮我们将文件名作个排序的记录。有时候系统也会通过调度来帮忙 RPM 数据库的重新创建。

  • 删除缓存

  某些软件在运行中会产生一些缓存,但是当这个软件关闭时,这些缓存可能并不会主动的被删除。 有些缓存则有时间性,如果超过一段时间后,这个缓存就没有效用了,此时删除这些缓存就是一件重要的工作,否则磁盘容量会被耗光。系统通过计划任务来调度执行名为 tmpwatch 的指令来删除这些缓存。

  • 与网络服务有关的分析行为

  如果安装类似 WWW 服务器软件 (apache),那么你的 Linux 系统通常就会主动的分析该软件的登录文件。 同时Linux 系统会自动检查某些凭证与认证的网络信息是否过期的问题。

1.3 仅执行一次的计划任务

1.3.1 atd 的启动与 at 运行的方式

  要使用单一工作调度时,我们的 Linux 系统上面必须要有负责这个调度的服务,那就是 atd。不过并非所有的 Linux distributions 都默认会把他打开的,所以,某些时刻我们必须要手动将他启用才行。 启用的方法很简单,就是这样:

[root@study ~]# systemctl restart atd  # 重新启动 atd 这个服务
[root@study ~]# systemctl enable atd   # 让这个服务开机就自动启动
[root@study ~]# systemctl status atd   # 查阅一下 atd 目前的状态
atd.service - Job spooling tools
   Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)       # 是否开机启动
   Active: active (running) since Thu 2015-07-30 19:21:21 CST; 23s ago # 是否正在运行中
 Main PID: 26503 (atd)
   CGroup: /system.slice/atd.service
           └─26503 /usr/sbin/atd -f

Jul 30 19:21:21 study.centos.vbird systemd[1]: Starting Job spooling tools...
Jul 30 19:21:21 study.centos.vbird systemd[1]: Started Job spooling tools.

at 的运行方式

  既然是计划任务,那么应该会有产生计划工作的方式,并且将这些计划工作排进行程表中。那么产生工作的方式是怎么进行的? 事实上,我们使用 at 这个指令来产生所要运行的工作,并将这个工作以文本文件的方式写入 /var/spool/at/ 目录内,该工作便能等待 atd 这个服务的取用与执行了。

  不过,并不是所有的人都可以进行 at 计划任务。为什么?因为安全~ 很多主机被“劫持”后,最常发现的就是他们的系统当中多了很多的骇客程序 (cracker program), 这些程序可能运用计划任务来执行或收集系统信息,并定时的回报给黑客! 所以,除非是你认可的帐号,否则先不要让他们使用 at 。那怎么实现 a1t 的管控呢?

  我们可以利用 /etc/at.allow 与 /etc/at.deny 这两个文件来进行 at 的使用限制。加上这两个文件后, at 的工作情况其实是这样的:

  1. 先找寻 /etc/at.allow 这个文件,写在这个文件中的使用者才能使用 at ,没有在这个文件中的使用者则不能使用 at (即使没有写在 at.deny 当中);
  2. 如果 /etc/at.allow 不存在,就寻找 /etc/at.deny 这个文件,若写在这个 at.deny 的使用者则不能使用 at ,而没有在这个 at.deny 文件中的使用者,就可以使用 at ;
  3. 如果两个文件都不存在,那么只有 root 可以使用 at 这个指令。

  etc/at.allow 是管理较为严格的方式,而 /etc/at.deny 则较为松散 (因为帐号没有在该文件中,就能够执行 at 了)。在一般的 distributions 当中,由于假设系统上的所有用户都是可信任的, 因此系统通常会保留一个空的 /etc/at.deny 文件,意思是允许所有人使用 at 指令。 

1.3.2 实际运行单一计划任务

  这个指令的运行非常简单,将 at 加上一个时间即可。基本的语法如下:

[root@study ~]# at [-mldv] TIME
[root@study ~]# at -c 任务号码
选项与参数:
-m  :当 at 的任务完成后,即使没有输出信息,亦以 email 通知使用者该工作已完成。
-l  :at -l 相当于 atq,列出目前系统上面的所有该使用者的 at 调度;
-d  :at -d 相当于 atrm ,可以取消一个在 at 调度中的任务;
-v  :可以使用较明显的时间格式列出 at 调度中的任务列表;
-c  :可以列出后面接的该项任务的实际指令内容。

TIME:时间格式,这里可以定义出“什么时候要进行 at 这项工作”的时间,格式有:
  HH:MM				ex> 04:00
	在今日的 HH:MM 时刻进行,若该时刻已超过,则明天的 HH:MM 进行此工作。
  HH:MM YYYY-MM-DD		ex> 04:00 2015-07-30
	强制规定在某年某月的某一天的特殊时刻进行该工作!
  HH:MM[am|pm] [Month] [Date]	ex> 04pm July 30
	也是一样,强制在某年某月某日的某时刻进行!
  HH:MM[am|pm] + number [minutes|hours|days|weeks]
	ex> now + 5 minutes	ex> 04pm + 3 days
	就是说,在某个时间点“再加几个时间后”才进行。

  老实说,这个 at 指令的下达最重要的地方在于“时间”的指定了。喜欢使用“ now + ... ” 的方式来定义现在过多少时间再进行工作,但有时也需要定义特定的时间点来进行。

范例一:再过五分钟后,将 /root/.bashrc 寄给 root 自己
[root@study ~]# at now + 5 minutes  <==记得单位要加 s 喔!
at> /bin/mail -s "testing at job" root < /root/.bashrc
at> <EOT>   <==这里输入 [ctrl] + d 就会出现 <EOF> 的字样!代表结束!
job 2 at Thu Jul 30 19:35:00 2015
# 上面这行信息在说明,第 2 个 at 工作将在 2015/07/30 的 19:35 进行!
# 而执行 at 会进入所谓的 at shell 环境,让你下达多重指令等待运行!

范例二:将上述的第 2 项工作内容列出来查阅
[root@study ~]# at -c 2
#!/bin/sh               <==就是通过 bash shell 的啦!
# atrun uid=0 gid=0
# mail root 0
umask 22
....(中间省略许多的环境变量项目)....
cd /etc/cron\.d || {
         echo 'Execution directory inaccessible' >&2
         exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER410efc26'
/bin/mail -s "testing at job" root < /root/.bashrc    # 这一行最重要!
marcinDELIMITER410efc26
# 你可以看到指令执行的目录 (/root),还有多个环境变量与实际的指令内容啦!

范例三:由于机房预计于 2015/08/05 停电,我想要在 2015/08/04 23:00 关机?
[root@study ~]# at 23:00 2015-08-04
at> /bin/sync
at> /bin/sync
at> /sbin/shutdown -h now
at> <EOT>
job 3 at Tue Aug  4 23:00:00 2015
# at 还可以在一个工作内输入多个指令

  事实上,当使用 at 时会进入一个 at shell 的环境,此时,最好使用绝对路径来下达指令。由于指令的下达与 PATH 变量有关, 同时与当时的工作目录也有关系 (如果有牵涉到文件的话),因此使用绝对路径来下达指令,会是比较一劳永逸的方法。举例来说,你在 /tmp 下达“ at now ”然后输入“ mail -s "test" root < .bashrc ”, 那个 .bashrc 的文件会是在哪里?答案是“ /tmp/.bashrc ”。因为 at 在运行时,会跑到当时下达 at 指令的那个工作目录。

  有些朋友会希望“我要在某某时刻,在我的终端机显示出 Hello 的字样”,然后就在 at 里面下达这样的信息“ echo "Hello" ”。等到时间到了,却发现没有任何讯息在屏幕上显示,这是为什么?这是因为 at 的执行与终端机环境无关,而所有 standard output/standard error output 都会传送到执行者的 mailbox 去。所以在终端机当然看不到任何信息,我们可以通过终端机的设备来处理。假如你在 tty1 登陆,则可以使用“ echo "Hello" > /dev/tty1 ”来取代。

   要注意的是,如果在 at shell 内的指令没有任何的信息输出,那么 at 默认不会发 email 给执行者的。 如果你想要让 at 无论如何都发一封 email 告知你是否执行了指令,那么可以使用“ at -m 时间格式 ”来下达指令。

   at 有另外一个优点,那就是“后台执行”。由于 at 计划任务的使用上,系统会将该项 at 工作独立出你的 bash 环境中, 直接交给系统的 atd 程序来接管,因此,当你下达了 at 的工作之后就可以立刻离线了, 剩下的工作就完全交给 Linux 管理即可。


at 任务管理

   万一下达 at 之后,才发现指令输入错误,利用 atq 与 atrm 将他移除。

[root@study ~]# atq
[root@study ~]# atrm (jobnumber)

范例一:查询目前主机上面有多少的 at 工作调度?
[root@study ~]# atq
3       Tue Aug  4 23:00:00 2015 a root
# 上面说的是:“在 2015/08/04 的 23:00 有一项工作,该项工作指令下达者为 
# root”而且,该项工作的工作号码 (jobnumber) 为 3 号

范例二:将上述的第 3 个工作移除
[root@study ~]# atrm 3
[root@study ~]# atq
# 没有任何信息,表示该工作被移除了

   利用 atq 来查询,利用 atrm 来删除错误的指令。


 batch:系统空闲时才执行后台任务

  其实 batch 是利用 at 来进行指令的下达,只是加入一些控制参数而已。这个 batch 神奇的地方在于:他会在 CPU 的工作负载小于 0.8 的时候,才进行你所下达的计划任务。工作负载的意思是: CPU 在单一时间点所负责的工作数量,不是 CPU 的使用率。

  当 CPU 的工作负载越大,代表 CPU 必须要在不同的工作之间进行频繁的工作切换。 因为一直切换工作,就会导致系统忙碌。系统如果很忙碌,还要额外进行 at ,不太合理,所以才有 batch 指令的产生。

  在 CentOS 7 下面的 batch 已经不再支持时间参数了,因此 batch 可以拿来作为判断是否要立刻执行后台任务的依据。我们下面来实验一下 batch,为了产生 CPU 较高的工作负载,因此我们用了 计算 pi 的脚本,连续执行 4 次这只程序, 来仿真高负载,然后来实现 batch 的工作现象:

范例一:请执行 pi 的计算,然后在系统闲置时,执行 updatdb 的任务
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
# 然后等待个大约数十秒的时间,之后再来确认一下工作负载的情况!
[root@study ~]# uptime
 19:56:45 up 2 days, 19:54,  2 users,  load average: 3.93, 2.23, 0.96

[root@study ~]# batch
at> /usr/bin/updatedb
at> <EOT>
job 4 at Thu Jul 30 19:57:00 2015

[root@study ~]# date;atq
Thu Jul 30 19:57:47 CST 2015
4       Thu Jul 30 19:57:00 2015 b root
# 可以看得到,明明时间已经超过了,却没有实际执行 at 的任务!

[root@study ~]# jobs
[1]   Running                 echo "scale=100000; 4*a(1)" | bc -lq &
[2]   Running                 echo "scale=100000; 4*a(1)" | bc -lq &
[3]-  Running                 echo "scale=100000; 4*a(1)" | bc -lq &
[4]+  Running                 echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# kill -9 %1 %2 %3 %4
# 这时先用 jobs 找出背景工作,再使用 kill 删除掉四个背景工作后,慢慢等待工作负载的下降

[root@study ~]# uptime; atq
 20:01:33 up 2 days, 19:59,  2 users,  load average: 0.89, 2.29, 1.40
4       Thu Jul 30 19:57:00 2015 b root
[root@study ~]# uptime; atq
 20:02:52 up 2 days, 20:01,  2 users,  load average: 0.23, 1.75, 1.28
# 在 19:59 时,由于 loading 还是高于 0.8,因此 atq 可以看得到 at job 还是持续再等待当中喔!
# 但是到了 20:01 时, loading 降低到 0.8 以下了,所以 atq 就执行完毕

  使用 uptime 可以观察到 1, 5, 15 分钟的“平均工作负载”量,因为是平均值,所以当删除掉四个工作后,工作负载不会立即降低, 需要一小段时间让这个 1 分钟平均值慢慢回复到接近 0 。当小于 0.8 之后的“整分钟时间”时,atd 就会将 batch 的工作执行。

   什么是“整分钟时间”呢?不论是 at 还是下面要介绍的 crontab,他们最小的时间单位是“分钟”,所以,基本上他们的工作是“每分钟检查一次”来处理的, 就是整分 (秒为 0 的时候)。

    batch 也是使用 atq/atrm 来管理的。

1.4 循环执行的计划任务

   循环执行的计划任务则是由 cron (crond) 这个系统服务来控制的。


 使用者的设置

   为了安全性的问题, 与 at 同样的,可以限制使用 crontab 的使用者帐号。使用的限制数据有:

  • /etc/cron.allow
    将可以使用 crontab 的帐号写入其中,若不在这个文件内的使用者则不可使用 crontab;
  • /etc/cron.deny
    将不可以使用 crontab 的帐号写入其中,若未记录到这个文件当中的使用者,就可以使用 crontab 。

  以优先顺序来说, /etc/cron.allow 比 /etc/cron.deny 要优先, 而判断上面,这两个文件只选择一个来限制而已,因此,建议只要保留一个即可, 免得影响自己在设置上面的判断。一般来说,系统默认是保留 /etc/cron.deny , 你可以将不想让他执行 crontab 的那个使用者写入 /etc/cron.deny 当中,一个帐号一行。

  当使用者使用 crontab 这个指令来创建计划任务之后,该项工作就会被记录到 /var/spool/cron/ 里面去了,而且是以帐号来作为判别的。举例来说, dmtsai 使用 crontab 后, 他的任务会被记录到 /var/spool/cron/dmtsai 里。但请注意,不要使用 vi 直接编辑该文件, 因为可能由于语法错误,会导致无法执行 cron 。另外, cron 执行的每一项工作都会被记录到 /var/log/cron 这个日志文件中,所以,如果你的 Linux 不知道有否被植入木马时,也可以查看一下 /var/log/cron 这个日志文件。

  crontab 的语法:

[root@study ~]# crontab [-u username] [-l|-e|-r]
选项与参数:
-u  :只有 root 才能进行这个任务,亦即帮其他使用者创建/移除 crontab 计划任务;
-e  :编辑 crontab 的工作内容
-l  :查阅 crontab 的工作内容
-r  :删除所有的 crontab 的任务内容,若仅要移除一项,请用 -e 去编辑。
范例一:用 dmtsai 的身份在每天的 12:00 发信给自己
[dmtsai@study ~]$ crontab -e
# 此时会进入 vi 的编辑画面让您编辑工作!注意到,每项工作都是一行。
0   12  *  *  * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
#分 时 日 月 周 |<==============指令串========================>|

   每项工作 (每行) 的格式都是具有六个字段,这六个字段的意义为:

  周的数字为 0 或 7 时,都代表“星期天”的意思。

    另外,还有一些辅助的字符,大概有下面这些:

  搭配几个例子练习看看:

 例一:

   在每年 5 月 1 日的 23:59 发一封信,信在 /home/dmtsai/lover.txt 。

使用 crontab -e 进入编辑:

 59 23 1 5 * mail kiki < /home/dmtsai/lover.txt

 例二:

  每五分钟需要执行 /home/dmtsai/test.sh 一次

 */5 * * * * /home/dmtsai/test.sh

   指令下达时,最好使用绝对路径。


  查询使用者目前的 crontab 内容

[dmtsai@study ~]$ crontab -l
0 12 * * * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
59 23 1 5 * mail kiki < /home/dmtsai/lover.txt
*/5 * * * * /home/dmtsai/test.sh
30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt

# 注意,若仅想要移除一项工作而已的话,必须要用 crontab -e 去编辑~
# 如果想要全部的工作都移除,才使用 crontab -r 喔!
[dmtsai@study ~]$ crontab -r
[dmtsai@study ~]$ crontab -l
no crontab for dmtsai

 1.5 系统配置文件: /etc/crontab, /etc/cron.d/*

  “ crontab -e ”是针对使用者的 cron 来设计的,如果是“系统的计划任务”时,不需要这么做,你只要编辑 /etc/crontab 这个文件就可以。需要特别注意的是 crontab -e 这个 crontab 其实是 /usr/bin/crontab 这个可执行文件,但是 /etc/crontab 可是一个“纯文本文件”。

  cron 这个服务的最低检测限制是“分钟”,“ cron 会每分钟去读取一次 /etc/crontab 与 /var/spool/cron 里面的数据内容 ”。

  但是某些原因或者是其他的 Unix 系统中,由于 crontab 是读到内存当中的,所以在你修改完 /etc/crontab 之后,可能并不会马上执行, 这个时候请重新启动 crond 这个服务 systemctl restart crond

  看一下这个 /etc/crontab 的内容

[root@study ~]# cat /etc/crontab
SHELL=/bin/bash                     <==使用哪种 shell 接口
PATH=/sbin:/bin:/usr/sbin:/usr/bin  <==可执行文件搜寻路径
MAILTO=root                         <==若有额外STDOUT,以 email将数据送给谁

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed

  这个文件与将我们下达 crontab -e 的内容几乎完全一模一样,只是有几个地方不太相同:

  • MAILTO=root:
    这个项是说,当 /etc/crontab 这个文件中的计划任务的指令发生错误时,或者是该工作的执行结果有 STDOUT/STDERR 时,会将错误信息或者是屏幕显示的信息传给谁?默认是由系统直接寄发一封 mail 给 root 。不过, 由于 root 并无法在用户端中以 POP3 之类的软件收信,因此,通常都将这个 e-mail 改成自己的帐号,好让我随时了解系统的状况。例如: MAILTO=dmtsai@my.host.name 。
  • PATH=....:
    这里是可执行文件的搜寻路径,使用默认的路径设置就已经很足够了。
  • “分 时 日 月 周 身份 指令”七个字段的设置
    这个 /etc/crontab 里面可以设置的基本语法与 crontab -e 不太相同。前面同样是分、时、日、月、周五个字段, 但是在五个字段后面接的并不是指令,而是一个新的字段,那就是“执行后面那串指令的身份”。这与使用者的 crontab -e 不相同。由于使用者自己的 crontab 并不需要指定身份,但 /etc/crontab 里面当然要指定身份。以上面的内容来说,系统默认的例行性工作是以 root 的身份来进行的。

crond 服务读取配置文件的位置 

   一般来说,crond 默认有三个地方会有执行脚本配置文件,他们分别是:

  • /etc/crontab
  • /etc/cron.d/*
  • /var/spool/cron/*

  这三个地方中,跟系统的运行比较有关系的两个配置文件是放在 /etc/crontab 文件内以及 /etc/cron.d/* 目录内的文件, 另外一个是跟用户自己的工作比较有关的配置文件,就是放在 /var/spool/cron/ 里面的文件群。

  现在来看看 /etc/cron.d 里面的东西:

[root@study ~]# ls -l /etc/cron.d
-rw-r--r--. 1 root root 128 Jul 30  2014 0hourly
-rw-r--r--. 1 root root 108 Mar  6 10:12 raid-check
-rw-------. 1 root root 235 Mar  6 13:45 sysstat
-rw-r--r--. 1 root root 187 Jan 28  2014 unbound-anchor
# 除了 /etc/crontab 之外,crond 的配置文件还真不少,上面就有四个设置!
# 先让我们来瞧瞧 0hourly 这个配置文件的内容吧!

[root@study ~]# cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
# 内容跟 /etc/crontab 几乎一模一样!但实际上是有设置值的,就是最后一行!

  另外,请注意一下上面表格中提到的最后一行,每个整点的一分会执行“ run-parts /etc/cron.hourly ”这个指令~这个可执行文件是 shell script,run-parts 脚本会在大约 5 分钟内随机选一个时间来执行 /etc/cron.hourly 目录内的所有可执行文件。因此,放在 /etc/cron.hourly/ 的文件,必须是能被直接执行的指令脚本。

   除了自己指定 crond 配置文件之外,你也可以直接将指令放置到(或链接到)/etc/cron.hourly/ 目录下, 则该指令就会被 crond 在每小时的 1 分开始后的 5 分钟内,随机取一个时间点来执行。

  在 /etc/ 下面其实还有 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/,那三个目录是代表每日、每周、每月各执行一次。跟 /etc/cron.hourly/ 不太一样的是,那三个目录是由 anacron 所执行的,而 anacron 的执行方式则是放在 /etc/cron.hourly/0anacron 里面~跟前几代 anacron 是单独的 service 不太一样。


 注意事项

  有的时候,用系统的 cron 来创建计划任务时,要注意一些使用方面的问题。 举例来说,如果我们有四个工作都是每五分钟要进行一次,那么是否这四个动作全部都在同一个时间点进行? 如果同时进行,该四个动作又很耗系统资源,如此一来,每五分钟的某个时刻不是会让系统很忙? 此时需要分配执行时间。

  • 资源分配不均的问题

  当大量使用 crontab 的时候,最严重的问题就是“系统资源分配不均”。

  如果每个流程都在同一个时间启动的话,这个时候就必须要分别设置,可以这样做:

[root@study ~]# vim /etc/crontab
1,6,11,16,21,26,31,36,41,46,51,56 * * * * root  CMD1
2,7,12,17,22,27,32,37,42,47,52,57 * * * * root  CMD2
3,8,13,18,23,28,33,38,43,48,53,58 * * * * root  CMD3
4,9,14,19,24,29,34,39,44,49,54,59 * * * * root  CMD4

  那个“ , ”分隔的时候,不要有空白字符。如此一来, 则可以将每五分钟工作的流程分别在不同的时刻来工作。

  • 取消不要的输出项目

  当有执行成果或者是执行的项目中有输出的数据时,该数据将会 mail 给 MAILTO 设置的帐号 ,如果有一个调度一直出错(例如 DNS 的侦测系统当中,若 DNS 上层主机挂掉,那么你就会一直收到错误信息),这时直接以“数据流重导向”将输出的结果输出到 /dev/null 这个垃圾桶当中。

  • 安全检查

  检查 /var/log/cron 的内容来查看是否有非法设置的 cron 被执行了。

  • 周与日月不可同时并存

  不可以设置「几月几号且星期几」。

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

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

  问题是,若是该工作非常重要 (例如例行备份), 所以其实你还是希望在下个星期天之前的某天还是进行一下比较好~那你该怎办?自己手动执行?如果你恰好忘了,这时候就得要靠 anacron 这个指令的功能了,它可以主动帮你进行时间到了但却没有执行的调度。


anacron

  anacron 存在的目的就在处理非 24 小时一直启动的 Linux 系统的 crontab 的执行,以及因为某些原因导致的超过时间而没有被执行的调度工作。

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

  anacron 默认会以一天、七天、一个月为期去监测系统未进行的 crontab 任务。

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

  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 程序结束。

  现在我们知道了为什么 CentOS 开机过后约 1 小时左右系统会有一小段时间的忙碌,而且硬盘会跑个不停。那就是因为 anacron 正在执行过去 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/ 里面的未进行的各项工作调度。


   最后,我们来总结一下本章谈到的许多配置文件与目录的关系,这样我们才能了解 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/ 内的可执行文件,以进行固定周期需要执行的指令。

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

 

posted @ 2022-12-07 11:35  莫莫君不恋爱  阅读(183)  评论(0编辑  收藏  举报