# 仅执行一次的工作排程
# atd 的启动
atd 并非所有的 distribution 都会预设打开,因此掌握他的启动和关闭等方式
systemctl restart atd # 重新启动 atd 服务
systemctl enable atd # 开机自动启动
systemctl status atd # 查询 atd 状态
2
3
[root@study ~]# systemctl status atd
● atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
Active: active (running) since 五 2020-03-06 13:31:07 CST; 25min ago
Main PID: 1382 (atd)
Tasks: 1
CGroup: /system.slice/atd.service
└─1382 /usr/sbin/atd -f
3月 06 13:31:07 study.centos.mrcode systemd[1]: Started Job spooling tools.
# 上面显示 enabled 和 actice(running) 标识开机启动,和正在运行中
2
3
4
5
6
7
8
9
10
11
# at 的运行方式
使用 at 指令产生的工作,会以文本方式写入 /var/spool/at/
目录内,该工作等待 atd 这个服务的取用与执行
另外为了安全,不要随意吧 at 指令执行权限下发,否则有黑客会使用定时任务来收集数据等情况
可以利用 /etc/at.allow
和 /etc/at.deny
文件来进行 at 的使用限制,加上这两个文件后,at 的工作情况如下:
- 先查找
/etc/at.allow
文件,在该文件中的使用者才能使用 at - 如果
/etc/at.allow
不存在,就查找/etc/at.deny
文件,写在这个at.deny
中的使用者无法使用 at - 如果两个文件都不存在,则只有 root 可以使用 at 指令
那么两个文件的含义如下:
at.allow
:严格限制,只有存在该文件中才能使用at.deny
:宽松限制,不存在该文件中则可以使用,也就是说,如果该文件是一个空文件,并且没有 at.allow 文件,那么就表示任何人都可以使用 at 指令
# at 语法
at [-mldv] TIME
at -c 工作号码
选项与参数:
-m:当 at 工作完成后,即使没有输出信息,也以 email 通知使用者该工作已完成
-l:at -l 相当于 atq,列出目前系统上的所有该用户的 at 排程
-d:at -d 相当于 atrm,可以取消一个再 at 排程中的工作
-v:可以使用较明显的时间格式列出 at 排程中的任务栏表
-c:可以列出后面接的该项工作的实际指令内容
TIME:时间格式,定义什么时候要进行 at 工作的时间,格式有:
HH:MM 如 4:00,在今日 4 点执行,若该时刻已过,则在明天的 4 点执行
HH:MM YYYY-MM-DD 如 4:00 2020-03-06 ,就在该时间点执行
HH:MM[am|pm] [Month] [Date] 如:04:00pm July 30,就在该时刻执行
HH:MM[am|pm] + number [minutes|hours|days|weeks]
如:now + 5 minutes、04pm + 3 days
在某个时间点再 + 几个时间后才执行
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
可以看到,该指令的复杂的就是时间的指定了
# 范例 1: 5 分钟后,将 /root/.bashrc 寄给 root 自己
[root@study ~]# at now + 5 minutes # 按回车后,输入要执行的指令
at> /bin/mail -s "testing at job" root < /root/.bashrc
at> <EOT> # 需要使用 ctrl + d 结束输入
job 3 at Fri Mar 6 14:22:00 2020
# at 工作已经创建,他的 ID 是 3, 会在 2020-03-06 14:22:00 执行
# 上面使用 at 指令会进入 at shell 环境,让你下达多重指令的运行
2
3
4
5
6
7
8
# 范例 2:将上述第 3 项工作内容查询出来
[root@study ~]# at -c 3
#!/bin/sh # 可以看出来是通过 bash shell 执行的
# atrun uid=0 gid=0
# mail mrcode 0
umask 22
。。。。。
cd /root || {
echo 'Execution directory inaccessible' >&2
exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER4065fff8'
# 下面这一行就是我们要执行的指令了
/bin/mail -s "testing at job" root < /root/.bashrc
marcinDELIMITER4065fff8
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
上面没有写出来的很多类容,大部分是设置了很多环境变量。
# 范例 3:由于机房预计 2020-03-08 停电,想要在 2020-03-07 23:00 关机
[root@study ~]# at 23:00 2020-03-07
at> /bin/sync
at> /bin/sync
at> /sbin/shutdown -h now
at> <EOT>
job 5 at Sat Mar 7 23:00:00 2020
2
3
4
5
6
7
由于指令的下达与 PATH 变量有关,同时与当时的工作目录也有关联(如果涉及到文件),因此使用绝对路径来下达指令,比较不容易出问题,
举例说明:你在 /tmp 下达 at now
然后输入 mail -s "test" root < .bashrc
,那么该文件的指向则是 /tmp/.bashrc
,因为 at 在运行时,会跑到当时下达 at 指令的那个工作目录
还有一个需要注意的,at 的执行与终端机环境无关,而所有 standard output/standard error output 都会传送到执行者的 mailbox 去,所以在 at 中执行 echo "Hello"
,并不会再终端机上看到该信息。有种方法可以达到显示在终端机上 echo "hello" > /dev/tty1
,把输出信息定向给了具体的 tty 终端机,前提是你登录了该终端机
还记得 -m
指令吗,如果 at 执行后,没有输出任何信息,则不会发送 email 给执行者的,使用 -m 指定之后,无论有没有输出信息,都会发送
还有 at 是在背景执行的,与 bash 的 nohup(第 16 章)类似,系统会将该项 at 工作独立出你的 bash 环境中,直接交给系统的 atd 程序来接管,因此下达了 at 的工作后,就可以脱机了(你断开登录的 tty 之后,不会让 at 执行工作也失效)。
# at 工作的管理
可以对 at 的查询和移除等工作
atq
atrm (jobnumber)
2
# 范例 1:查询目前主机上有多少 at 工作排程
[root@study ~]# atq
# 编号 日期 谁下达的
5 Sat Mar 7 23:00:00 2020 a root
# 这里看不出来内容,还可以利用上面的 at -c 5 来确认
[root@study ~]# at -c 5
${SHELL:-/bin/sh} << 'marcinDELIMITER464e26fe'
/bin/sync
/bin/sync
/sbin/shutdown -h now
# 这里就能看到,是上面关机的任务
# 范例 2: 删除上面的任务
[root@study ~]# atrm 5
[root@study ~]# atq
# 没有信息输出,标识没有任务了
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# batch:系统空闲时才进行背景任务
batch 会再 CPU 的工作负载小于 0.8 的时候,才进行 at 中的任务;
工作负载:CPU 在单一时间点所负责的工作数量,不是 CPU 使用率。比如:有一个程序需要一直使用 CPU 运算功能,那么 CPU 的使用率可能达到 100%,但是 CPU 的工作负载则是趋近于 1,如果有两个这样的程序,那么 CPU 使用率还是 100%,但是工作负载就变成了 2,也就是可以看成为多线程,CPU 同时为几个线程提供服务
所以 CPU 工作负载越大,CPU 越忙碌
CentOS 下的 batch 已经不再支持时间参数了,因此 batch 可以拿来作为判断是否要立刻执行背景程序的依据,为了模拟 CPU 较高的工作负载,使用 12 章里面的计算 PI 的脚本,连续执行 4 次这样的程序。
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[1] 4677
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[2] 4679
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[3] 4681
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[4] 4683
# uptime 查看负载
[root@study ~]# uptime
17:04:28 up 3:33, 1 user, load average: 0.47, 0.11, 0.08
[root@study ~]# uptime
17:04:33 up 3:33, 1 user, load average: 0.75, 0.18, 0.10
[root@study ~]# uptime
17:04:39 up 3:34, 1 user, load average: 1.33, 0.32, 0.15
# 可以看到,平均负载飙升到 1.33 了
[root@study ~]# batch
at> /usr/bin/updatedb
at> <EOT>
job 6 at Fri Mar 6 17:05:00 2020
[root@study ~]# date;atq
2020年 03月 06日 星期五 17:06:25 CST
6 Fri Mar 6 17:05:00 2020 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 &
# 使用 jobs 找出背景功能,再使用 kill 删除掉 4 个背景工作后,等待工作负载的下降
[root@study ~]# kill -9 %1 %2 %3 %4
# 需要等待工作负载降低到 0.8 以下
[root@study ~]# uptime; atq
17:09:32 up 3:38, 1 user, load average: 2.29, 2.30, 1.10
6 Fri Mar 6 17:05:00 2020 b root
[root@study ~]# uptime; atq
17:09:38 up 3:39, 1 user, load average: 2.10, 2.27, 1.09
6 Fri Mar 6 17:05:00 2020 b root
[root@study ~]# uptime; atq
17:11:20 up 3:40, 1 user, load average: 0.52, 1.63, 0.99
6 Fri Mar 6 17:05:00 2020 = root
[root@study ~]# uptime; atq
17:11:21 up 3:40, 1 user, load average: 0.52, 1.63, 0.99
# 这里降低到 0.52 还能看到还没有执行,多等待下,就会发现不执行了,
# 这个是因为指令的执行完成也需要一定时间的
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
平均工作负载:是统计的 1 分钟内的平均值,当小于 0.8之后的「整分钟时间」,atd 会执行 batch 的工作
整分钟时间:无论 at 还是 crontab,他们最小的时间单位是分钟,所以基本上,他们工作是 每分钟检查一次 ,就是整分(秒为 9 的时候)。另外 batch 也是使用 atq/atrm 来管理的