一、为什么需要定时任务?

这个其实是我在工作当中遇到的一个问题,我需要在非工作时间,比如晚上0点,自动执行一个脚本,来重启算法服务。这其实也是卡在一个其他客户不用上班的时间,工作时间点肯定就不能进行算法服务的重启操作了,这对于客户的损失是比较大的。因此,借此场景来学习Linux定时任务的设置。

Linux设置定时任务的好处如下:

  • 设置自动化重复工作,解放双手
  • 保障系统维护在非工作时间执行
  • 确保关键任务按时完成,避免人为遗忘

二、核心工具:cron与at

Linux系统提供了多种定时任务工具,其中最常用的有cron和at,此外还有batch、systemd-timer等工具。不过目前主要使用的是cron和at。因此,下面主要介绍这两个工具的使用。

2.1 cron:最常用的周期性定时任务系统

什么是cron?

cron是Linux系统中最经典、最常用的定时任务调度器,用于周期性执行命令或脚本。它通过crontab文件定义任务,由cron守护进程(crond)在后台持续运行并检查任务执行时间,其中系统级任务存储在/etc/crontab和/etc/cron.d/目录下,用户级任务通过crontab命令管理。

工作原理:

  1. 用户创建或编辑任务:用户通过 crontab 命令创建或编辑定时任务。执行 crontab -e 命令时,系统会调用默认的文本编辑器打开一个临时文件,用户可以在其中按照 cron 的语法格式添加、修改或删除定时任务。编辑完成并保存退出后,该文件内容会被处理成合法的定时任务信息。
  2. 任务存储:经过处理的定时任务信息会被保存到 /var/spool/cron/ 目录下以用户名命名的专属文件中。每个用户的定时任务都独立存储在该目录下对应的文件里,保证了不同用户任务的隔离性。
  3. 守护进程检查crond 守护进程在系统后台持续运行,每分钟会对 /var/spool/cron/ 目录下的所有用户专属文件,以及 /etc/crontab/etc/cron.d/ 目录下的系统级任务文件进行一次全面检查。它会解析每个任务的时间表达式,判断是否有任务到达执行时间。
  4. 任务执行:当 crond 守护进程检查到某个任务到达指定的执行时间时,会 fork 一个子进程来执行该任务。之所以创建子进程,是为了保证 crond 守护进程本身可以继续正常运行,不受任务执行的影响。任务执行完成后,子进程会自动结束。

优点:

  • 支持复杂的时间表达式,可精确到分钟级别
  • 任务执行结果可通过邮件通知(默认配置)
  • 支持系统级和用户级任务分离
  • 几乎所有Linux发行版都预装并默认启用

缺点:

  • 配置相对复杂,需要记忆特殊字符的含义
  • 不支持任务依赖关系
  • 当系统关机或重启时,错过的任务不会自动执行(需配合anacron解决)

适用场景:

  • 需要定期执行的系统维护任务(如日志清理、备份)
  • 周期性的数据处理或报表生成
  • 定时启动/关闭服务或应用程序

crontab命令:管理定时任务的入口

  • crontab -e:编辑当前用户的定时任务
  • crontab -l:列出当前用户的定时任务
  • crontab -r:删除当前用户的所有定时任务
  • crontab -u username -e:编辑指定用户的定时任务(需要root权限)

2.2 at:一次性定时任务工具

什么是at?

at 是用于执行一次性定时任务的工具,可在指定时间点执行一次命令或脚本。与 cron 不同,at 任务执行完毕后会自动删除,由 atd 守护进程负责管理和执行。

工作原理:

  1. 用户创建任务:用户使用 at 命令指定任务的执行时间和要执行的命令。at 命令支持多种时间指定方式,如绝对时间(例如 at 23:00 tomorrow)和相对时间(例如 at now + 30 minutes)。执行命令后,用户需要输入要执行的具体命令,输入完成后按 Ctrl + D 结束输入。
  2. 任务存储:输入完成后,系统会对任务信息进行处理,将任务保存到 /var/spool/at/ 目录下。任务会被存储为一个文件,文件名包含任务的唯一标识,确保每个任务都能被准确识别和管理。
  3. 守护进程检查atd 守护进程在系统后台持续运行,每分钟会检查 /var/spool/at/ 目录下的任务文件。它会解析每个任务文件中的时间信息,判断是否有任务到达执行时间。
  4. 任务执行与清理:当 atd 守护进程检查到某个任务到达指定的执行时间时,会 fork 一个子进程来执行该任务。这样可以保证 atd 守护进程本身能够继续正常运行,不受任务执行的影响。任务执行完成后,atd 会自动删除对应的任务文件,清理任务记录。

这里给个一个简单的 at 命令使用示例,该示例会在明天 10 点执行关机命令(使用at要确保Linux已经安装了这个命令):

1
2
at 10:00 tomorrow # 先执行命令
shutdown -h now # 然后输入到时间点要执行的命令

优点:

  • 语法简单直观,容易学习和使用
  • 适合临时的、一次性的任务调度
  • 支持多种时间指定方式(如绝对时间、相对时间)

缺点:

  • 不支持周期性任务
  • 任务执行结果默认通过邮件发送,可能被忽略
  • 当系统关机或重启时,错过的任务不会自动执行

适用场景:

  • 延迟执行某个命令(如30分钟后关闭系统)
  • 在特定时间点执行一次性数据处理
  • 安排在非工作时间执行的临时任务

与cron的主要区别:

  • cron用于周期性任务,at用于一次性任务
  • cron任务会被保存并重复执行,at任务执行后自动删除
  • cron配置相对复杂,at语法更简单直观

2.3 其他定时任务工具

batch 是一个用于在系统负载较低时执行一次性任务的工具。它与 at 类似,但不指定具体执行时间,而是在系统负载低于某个阈值时才执行,适合用于执行资源密集型任务,以此避免影响系统正常运行。

systemd-timer:新时代的定时任务方案:随着systemd的普及,systemd-timer逐渐成为替代cron的新选择。它支持更精确的时间控制、任务依赖关系和事件触发,配置灵活,但学习曲线较陡峭。

三、cron基础使用教程

目前我在工作中所使用的也是cron居多,基本上都是要在服务器上执行一些定时任务,这个cron使用起来较为简单,很快就可以把一个定时任务给编写出来。下面具体介绍一下cron的基础使用方式。

3.1 基本语法与格式

cron的配置文件遵循严格的语法格式,每行代表一个定时任务,格式如下:

1
分 时 日 月 周 要执行的命令

时间字段详细解析

  • :取值范围 0-59,表示分钟
  • :取值范围 0-23,表示小时
  • :取值范围 1-31,表示日期
  • :取值范围 1-12,表示月份
  • :取值范围 0-7(0和7都代表星期日),表示星期几

特殊字符含义及示例

  • *:表示所有可能的值,例如在”分”字段使用*,表示每分钟执行一次
  • /:表示间隔,例如在”分”字段使用*/5,表示每5分钟执行一次
  • -:表示范围,例如在”时”字段使用9-17,表示9点到17点之间每个小时执行一次
  • ,:表示多个值,例如在”周”字段使用1,3,5,表示周一、周三、周五执行

通过上面时间字段+特殊字符,我们可以组合出各种不同的定时任务。具体怎么组合就要看实际的业务场景了,同时也需要大家发挥自己的创意和经验🌈。下面给出一些组合的示例。

示例效果说明

  • 0 8 * * * command:每天早上8点整执行命令
  • */15 * * * * command:每15分钟执行一次命令
  • 0 12 * * 1-5 command:周一至周五中午12点执行命令
  • 30 2 1,15 * * command:每月1日和15日凌晨2点30分执行命令

3.2 常用命令速查

crontab -e:编辑定时任务

使用步骤

  1. 执行命令后,系统会打开默认文本编辑器(通常是vi或nano)
  2. 在编辑器中按照cron语法添加或修改任务
  3. 保存并退出编辑器,任务会自动生效

效果:添加或更新用户的定时任务列表

crontab -l:查看当前任务

使用步骤:直接在终端执行命令

效果:以文本形式显示当前用户的所有定时任务

crontab -r:删除所有任务

使用步骤:直接在终端执行命令(注意:此操作不可逆)

效果:删除当前用户的所有定时任务

警告:使用此命令前请务必先用crontab -l备份任务列表

crontab -u username -e:管理其他用户的任务

使用步骤

  1. 以root用户身份执行命令
  2. 编辑指定用户的定时任务
  3. 保存并退出编辑器

效果:添加或更新指定用户的定时任务列表

权限要求:需要root权限才能管理其他用户的任务

四、实用示例:服务场景配置

下面以”每日凌晨2点自动备份数据库”为例,详细演示从crontab -e开始到任务设置完成的完整流程。

4.1 场景需求

每天凌晨2点自动备份MySQL数据库,并将备份文件压缩存储到指定目录。

4.2 实现步骤

步骤1:创建备份脚本

首先,我们需要创建一个数据库备份脚本:

1
2
3
# 创建备份脚本文件
mkdir -p /backup/scripts
vi /backup/scripts/mysql_backup.sh

在脚本中添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# MySQL数据库备份脚本

# 配置信息
DB_USER="root"
DB_PASS="your_password"
DB_NAME="your_database"
BKP_DIR="/backup/mysql"
BKP_TIME=$(date +%Y%m%d_%H%M%S)

# 创建备份目录
mkdir -p $BKP_DIR

# 执行备份
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BKP_DIR/${DB_NAME}_${BKP_TIME}.sql.gz

# 清理7天前的备份文件
find $BKP_DIR -name "${DB_NAME}_*.sql.gz" -mtime +7 -delete

# 记录日志
echo "备份完成: $BKP_DIR/${DB_NAME}_${BKP_TIME}.sql.gz" >> /var/log/mysql_backup.log

保存并退出编辑器,然后为脚本添加执行权限:

1
chmod +x /backup/scripts/mysql_backup.sh

上面的脚本可以是任何任务,比如我实际业务遇到的算法服务,需要定时调用接口,或者定时调用脚本。下面的步骤是通用的,只需要把要执行的命令替换为实际的命令即可。

步骤2:使用crontab -e添加定时任务

执行以下命令编辑定时任务:

1
crontab -e

系统会打开默认文本编辑器(通常会是vim,当然我的Linux默认是vim啦)。在编辑器中添加以下行:

1
0 2 * * * /backup/scripts/mysql_backup.sh

这表示每天凌晨2点(0分2时)执行备份脚本。

这里面的命令是要执行的命令,比如我上面的脚本,就是要执行的命令。也就是说你Linux怎么启动或者重启脚本,这里就怎么写!!本质上就是让Linux帮你在两点钟执行后面那个命令🤖

步骤3:保存并退出编辑器

  • 如果使用vi编辑器:按Esc键,然后输入:wq并按Enter键保存退出
  • 如果使用nano编辑器:按Ctrl+O保存,按Ctrl+X退出
  • 如果使用vim编辑器:按:wq并按Enter键保存退出

步骤4:验证定时任务是否添加成功

执行以下命令查看当前用户的定时任务:

1
crontab -l

如果成功添加,会看到类似以下输出:

1
0 2 * * * /backup/scripts/mysql_backup.sh

给大家看一下Linux实际的输出会是什么样子的?这是我自己设置的重启systemctl服务,重启脚本的时间是0点。

crontab -l 输出

五、避坑指南:常见问题排查

  • 定时任务不执行?检查这几点
    1. 命令路径是否正确
    2. 环境变量是否配置
    3. 文件权限是否足够

这里要补充一下,命令路径最好写绝对路径,不要写相对路径。因为定时任务是在系统后台执行的,所以相对路径是相对于系统的根目录,而不是相对于当前用户的目录。其次,要注意文件权限的设置,不同的用户有不同的权限,所以要根据实际情况来设置⌨