循环执行的例行性工作调度 crontab(定时任务)
15.1 例行性工作调度 不考虑硬件与服务器的链接状态,Linux帮助提醒很多任务。 Linux例行性工作是如何进行调度的? Linux调度就是通过 crontab 与 at 这两个东西 15.1.1 Linux工作调度的种类:at,cron 两种工作调度的方式: 一种是例行性的,每隔一定的周期要来办的事情,定时任务 一种是突发性的,就是每次做完以后就不在执行的,只调度一次 at:at是可以处理仅执行一次就结束调度的指令,不过要执行at时,必须要有 atd这个服务的支持才行。在某些新版的 distributions 中,atd 可能默认并没有启动,那么 at 这个指令就会失效呢!不过我们 CentOS 默认是启动的! crontab:crontab 这个指令所设置的工作将会循环的一直进行下去! 可循环的时间为分钟、小时、每周、每月或每年等。crontab 除了可以使用指令执行外,亦可编辑 /etc/crontab 来支持。 让 crontab 可以生效的服务则是 crond 这个服务! 15.1.2 CentOS Linux系统上常见的例行性工作 Linux系统常见的例行性任务有: ① 进行登录文件的轮替(log rotate):Linux会主动的将系统所发生的各种信息都记录下来,这就是登录文件(第十八章)。 系统会一直记录登录信息,所以登录文件将会越来越大,大型文件不但占容量还会造成读写性能的困扰,因此适时的将登陆文件数据挪一挪,让旧的数据与新的数据分别存放可以有效的记录登录信息。这就是 log rotate 的任务,这也是系统必要的例行任务。 ②登录文件分析 logwatch 的任务:如果系统发生软件问题、硬件错误、资安问题等,绝大部分的错误信息都会被记录到登录文件中, 因此系统管理员的重要任务之一就是分析登录文件。但你不可能手动通过 vim 等软件去检视登录文件,因为数据太复杂了! 我们的 CentOS 提供了一只程序“ logwatch ”来主动分析登录信息。 ③创建 locate 的数据库: 在第六章我们谈到的 locate 指令时, 我们知道该指令是通过已经存在的文件名数据库来进行系统上文件名的查询。我们的文件名数据库是放置到 /var/lib/mlocate/ 中。 问题是,这个数据库怎么会自动更新啊?这就是系统的例行性工作所产生的效果,系统会主动的进行 updatedb ! ④man page 查询数据库的创建: 与 locate 数据库类似的,可提供快速查询的 man pagedb 也是个数据库,但如果要使用 man page 数据库时,就得要执行 mandb 才能够创建好! 而这个 man page 数据库也是通过系统的例行性工作调度来自动执行的。 ⑤RPM 软件登录文件的创建: RPM (第二十二章) 是一种软件管理的机制。由于系统可能会常常变更软件, 包括软件的新安装、非经常性更新等,都会造成软件文件名的差异。为了方便未来追踪,系统也帮我们将文件名作个排序的记录, 有时候系统也会通过调度来帮 RPM 数据库的重新创建。 ⑥移除暂存盘: 某些软件在运行中会产生一些暂存盘,但是当这个软件关闭时,这些暂存盘可能并不会主动的被移除。 有些暂存盘则有时间性,如果超过一段时间后,这个暂存盘就没有效用了,此时移除这些暂存盘就是一件重要的工作! 否则磁盘容量会被耗光。系统通过例行性工作调度执行名为 tmpwatch 的指令来删除这些暂存盘。 ⑦与网络服务有关的分析行为: 如果你有安装类似 WWW 服务器软件 (一个名为 apache的软件),那么你的 Linux 系统通常就会主动的分析该软件的登录文件。 同时某些凭证与认证的网络信息是否过期的问题, Linux 系统也会很友好的进行自动检查。 15.2 仅执行一次的工作调度 at:单一工作调度的运行 15.3 循环执行的例行性工作调度 相对于 at 是仅执行一次的工作,循环执行的例行性工作调度则是由 cron (crond) 这个系统服务来控制的。 Linux系统上面原本就有非常多的例行性工作,因此这个系统服务是默认启动的。 使用者自己也可以进行例行性工作调度,所以,Linux也提供使用者控制例行性工作调度的指令(crontab) 15.3.1 使用者的设置 使用者想要创建循环型工作调度时使用的是 crontab 这个指令。为了安全性的问题与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 里面去,而且是以账号来作为判别的。 如下:root用户使用 crontab 后,工作会被记录到 /var/spool/cron/root 文件中去,不要使用 vi 直接编辑该文件,因为可能由于输入语法错误,会导致无法执行cron /var/spool/cron/ 中的内容: 另外,cron 执行的每一项工作都会被记录到 /var/log/cron 这个登录文件中,所以Linux不知道是否被植入木马时,也可以搜寻一下 /var/log/cron 这个登录文件 crontab语法: 例如: 默认情况下,任何使用者只要不被列入 /etc/cron.deny 当中,就可以直接使用 crontab -e 去编辑自己的例行性命令 整个过程就如上,会进入 vi 的编辑画面, 然后以一个工作一行来编辑。 而每项工作 (每行) 的格式都是具有六个字段,这六个字段的意义为: 周的数字为0或7时,都代表“星期天”的意思 辅助字符: 例如:每 5 分钟需要执行 /home/root/test.sh 一次,使用 crontab -e 进入编辑: * /5 * * * * /home/root/test.sh crontab 每个人都只有一个文件存在,就是在 /var/spool/cron 里面 指令下达时,最好使用绝对路径,这样比较不会找不到可执行文件 查询使用者目前的 crontab 内容: pay平台: 注意:只要删除某个 crontab的工作项目,使用 crontab -e 来重新编辑即可 使用 crontab -r 的参数,是会将所有的 crontab 数据内容都删除掉的 15.3.2 系统的配置文件: /etc/crontab,/etc/cron.d/* crontab -e 是针对使用者的 cron 来设计的 如果是“系统的例行性任务"时该怎么办?只需要编辑 /etc/crontab 这个文件就可以 crontab -e 这个 crontab 其实是 /usr/bin/crontab 这个可执行文件,但是 /etc/crontab 是一个纯文本文件,可以使用 root的身份编辑 cron 这个服务的最低侦测限制是 "分钟",所以 cron 会每分钟去读一次 /etc/crontab 与 /var/spool/cron 里面的数据内容 因此只要编辑完 /etc/crontab 这个文件,并存储之后,cron的设置就自动的会来执行了 Tips: 在 Linux 下面的 crontab 会自动的帮我们每分钟重新读取一次 /etc/crontab 的例行工作事项,但是某些原因或者是其他的 Unix 系统中,由于 crontab 是读到内存当中的,所以在修改完 /etc/crontab 之后,可能并不会马上执行,这时候需要重新启动 crond 这个服务 systemctl restart crond /etc/crontab 文件内容: MAILTO=root: 这个项是说,当 /etc/crontab 这个文件中的例行性工作的指令发生错误时,或者是该工作的执行结果有 STDOUT/STDERR 时,会将错误讯息或者是屏幕显示的讯息传给谁?默认当然是由系统直接寄发一封 mail 给 root 。不过, 由于 root 并无法在用户端中以 POP3 之类的软件收信,因此,可以将这个 e-mail 改成自己的帐号,可以随时了解系统的状况。例如: MAILTO=dmtsai@my.host.name PATH=....: 在第十章的 BASH 当中一直提到的可执行文件路径, 这里就是输入可执行文件的搜寻路径。使用默认的路径设置就已经足够了。 "分 时 日 月 周 身份 指令"七个字段的设置 /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/ 里面的文件群。 现在我们已经知道了 /var/spool/cron 以及 /etc/crontab 的内容. /etc/cron.d 中的内容: 内容跟 /etc/crontab 几乎一模一样,实际上最后一行是设置的值 注意一下上面表格中提到的最后一行,每个整点的一分会执行“ run-parts/etc/cron.hourly ”这个指令,什么是 run-parts 呢? 如果你有去分析一下这个可执行文件,会发现他就是 shell script,run-parts 脚本会在大约 5 分钟内随机选一个时间来执行 /etc/cron.hourly 目录内的所有可执行文件!因 放在 /etc/cron.hourly 的文件必须是能被直接执行的指令脚本,而不是分、时、日、月、周的设置值 如果自己开发新的软件,该软件要拥有自己的 crontab 定时指令时,就可以将“分、时、日、月、周、身份、指定”的配置文件放置到 /etc/cron.d/ 目录下,在此目录下的文件是 crontab 的配置文件脚本 Tips :以鸟哥来说,现在鸟哥有在开发一些虚拟化教室的软件,该软件需要定时清除一些垃圾防火墙规则, 那鸟哥就是将要执行的时间与指令设计好,然后直接将设置写入到 /etc/cron.d/newfile 即可!未来如果这个软件要升级, 直接将该文件覆盖成新文件即可!比起手动去分析 /etc/crontab 要单纯的多! 也就是说,除了自己指定分、时、日、月、周加上指令路径的 crond 配置文件之外,你也可以直接将指令放置到(或链接到)/etc/cron.hourly/ 目录下, 则该指令就会被 crond 在每小时的 1 分开始后的 5 分钟内,随机取一个时间点来执行啰!你无须手动去指定分、时、日、月、周就是了。 但是眼尖的朋友可能还会发现,除了可以直接将指令放到 /etc/cron.hourly/ 让系统每小时定时执行之外,在 /etc/ 下面其实还有 /etc/cron.daily/, /etc/cron.weekly/, /etc/cron.monthly/,那三个目录是代表每日、每周、每月各执行一次。不过,跟 /etc/cron.hourly/ 不太一样的是,那三个目录是由 anacron 所执行的,而 anacron 的执行方式则是放在 /etc/cron.hourly/0anacron 里面。跟前几代 anacron 是单独的 service 不太一样。 总结: 15.3.3 注意事项 取消不要的输出项目 15.4 可唤醒停机期间的工作任务 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 : 所以其实也仅仅是执行 anacron -s 的指令 anacron 的语法如下: 在我们的 CentOS 中,anacron 的进行其实是在每个小时都会被抓出来执行一次, 但是为了担心 anacron 误判时间参数,因此 /etc/cron.hourly/ 里面的 anacron 才会在文件名之前加个 0(0anacron),让 anacron 最先进行!就是为了让时间戳记先更新!以避免 anacron 误判 crontab 尚未进行任何工作的意思。 接下来我们看一下 anacron 的配置文件: /etc/anacrontab 的内容好了: 拿 /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/ 里头的未进行的各项工作调度 最后,我们来总结一下本章谈到的许多配置文件与目录的关系,这样我们才能了解 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/ 目录下,那么该工作就会定期,几乎一定会在一周内执行一次~如果你关机超过一周,那么一开机后的数个小时内,该工作就会主动的被执行. Tips :基本上,crontab 与 at 都是“定时”去执行,过了时间就过了!不会重新来一遍 anacron 则是“定期”去执行,某一段周期的执行~ 因此,两者可以并行,并不会互相冲突. 定时任务每部分的含义: 秒(0-59)、分(0-59)、时(0-23)、天(1-31)、月(1-12)、周(1-7)、年(1970-2099)* :代表任何值 ? : 也代表任何值,但只用于 Day-of-month 和 Day-of-Week ,当其中一个设置了条件时,另外一个就要用 ? 来表示“任何值” - : 用来表示范围,比如 Day-of-month 5-10 代表 5号到10号 , :用来添加附加的参数,比如 Hours 4,14 代表上午 4 点和下午两点 / : 用来代表增量以用来循环,比如 Hours 2/6 代表 2点,8点,下午2点,下午8点 L : 用于 Day-of-month 和 Day-of-Week, 代表最后1天,在Day-of-month中只用'L'就可以,在Day-of-week中用 'nL' 来代表是最后一个星期n W : 用于 Day-of-month, 代表最近工作日,比如 '15W', 如果15号那天是周六则取14号周五,如果是周日则取16号周一,其他情况不变 LW : 代表当月最后一个工作日 # : 用于 Day-of-Week, 'n#m'用于代表当月第m个 "周n"(根据n在week中的定义确定)