解决 多人编译 抢占资源问题, 使用 linux task spooler 工具.

1
2
3
4
5
6
7
task spooler is a Unix batch system where the tasks spooled run one after the other. The amount of
jobs to run at once can be set at any time. Each user in each system has his own job queue. The
tasks are run in the correct context (that of enqueue) from any shell/process, and its output/results
can be easily watched. It is very useful when you know that your commands depend on a lot of RAM,
a lot of disk use, give a lot of output, or for whatever reason it's better not to run them all at
the same time, while you want to keep your resources busy for maximum benfit. Its interface allows
using it easily in scripts.
1
2
3
4
5
6
7
8
9
10
11
12
task spooler 是一个简单的批处理程序, 他可以实现简单的队列功能, 当你有多个任务(假设3个任务)需要执行的时候,
每个任务都是比较消耗内存, 消耗cpu资源, 消耗IO资源的任务(类似的编译android镜像, repo更新android代码).
如果你让这3个任务同时执行,可能每个任务执行的都很慢,每个任务都在抢占系统资源(抢占cpu,抢占内存,抢占IO).
这个时候你可以使用 task spooler 命令来包装你的命令, 可以设置队列中的执行个数是1(默认是1, 也可以设置大于1,
服务器性能好的可以设置大于1,但是设置的太大也就没啥用了),
这样这3个任务会依次排队的执行, 这样的好处就是每个任务都能得到最大的系统资源, 3个任务顺序的整个执行下来说不定
执行时间还会小于3个同时执行的时间呢.


当一个服务器(尤其是研发的编译服务器)多个人使用的时候,这个每个人都在抢占系统资源,这个时候使用这个工具就能很好的
达到资源的合理利用了.每个人都能最大的使用系统资源.

1
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
tsp 工具  可以实现 多人共享一个队列. 这个队列默认只能同时执行一个任务, 当然也可以设置同时执行多个任务.
tsp 工具 执行命令的时候是克隆当时的环境变量的,例如你编译安卓 执行过了 source 执行过了了lunch, 这时候你只需要 tsp make就能编译了.

执行很简单的, 就是在你的命令前 加上 tsp

例如更新代码: tsp repo sync -cdj4 --no-tags
例如编译: tsp make -j64 (tsp命令同时会帮你保存命令的输出到文件的, 这样就可以保存编译日志了,事后可以查看)

$ tsp (这个是默认执行tsp命令, 如果队列没有任何任务,就是输出如下的样子)
ID State E-Level Times [run=0/1] Command &>Output

$ tsp -h
usage: tsp [action] [-ngfmdE] [-L <lab>] [-D <id>] [cmd...]
Actions:
-K kill the task spooler server
-C clear the list of finished jobs
-l show the job list (default action)
-S [num] get/set the number of max simultaneous jobs of the server.
-t [id] "tail -n 10 -f" the output of the job. Last run if not specified.
-c [id] like -t, but shows all the lines. Last run if not specified.
-p [id] show the pid of the job. Last run if not specified.
-o [id] show the output file. Of last job run, if not specified.
-i [id] show job information. Of last job run, if not specified.
-s [id] show the job state. Of the last added, if not specified.
-r [id] remove a job. The last added, if not specified.
-w [id] wait for a job. The last added, if not specified.
-k [id] send SIGTERM to the job process group. The last run, if not specified.
-u [id] put that job first. The last added, if not specified.
-U <id-id> swap two jobs in the queue.
-B in case of full queue on the server, quit (2) instead of waiting.
-h show this help
-V show the program version
Options adding jobs:
-n don't store the output of the command.
-d the job will be run only if the job before ends well
-D <id> the job will be run only if the job of given id ends well.
-O <out> output stdout and stderr to <out> file. If file already exists it will be overwritten.

1
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
使用前 就是 执行一下  tsp 命令, 如果tsp的服务端没有运行,第一次执行tsp命令就会启动 服务端.
服务端程序会一直运行的, 除非你执行了 tsp -K 杀死它.
$ tsp
ID State E-Level Times [run=0/1] Command &>Output
上面就是第一次执行的效果, 输出的队列是空的,

执行 ps命令 可以看到 后台有个 tsp 的进程了. 默认执行 tsp 是 和 执行 tsp -l 效果相同的.
$ ps -ef|grep tsp
buildsr+ 55191 1 0 16:42 ? 00:00:00 tsp
buildsr+ 55649 54613 0 16:43 pts/10 00:00:00 grep --color=auto tsp



下面介绍几个重要的选项.
-S 可以设置队列同时运行的任务数. 默认是1. 当多个人同时在一个服务器上工作,一个人在用tsp队列编译,
这个时候第二个人也想编译,但是默认并发是1个,这个第二个人的编译又比较急迫, 这时候可以使用 -S 选项
把并发数设置为2,这个时候第二个人的编译任务就会开始执行了,设置完最好再改回原来的1.保证只有一个并发
这样能让一个编译任务尽可能的利用系统资源.


如果第一次执行的命令是 tsp 加 <自己的命令> 例如下面这样:
$ tsp ls
0

这样ls这个命令就会放到 队列中执行, 因为是第一次, 这个ls命令会很快执行完成.

执行 ps命令 可以看到 后台有个 tsp ls进程了, 这里ls 就 你执行的哪个命令.
$ ps -ef|grep tsp
buildsr+ 35285 1 0 17:49 ? 00:00:00 tsp ls
buildsr+ 35336 34925 0 17:50 pts/14 00:00:00 grep --color=auto tsp



-c 选项 列出 某个任务的输出, 默认最后一个任务 的输出. -c 后面可以跟上 任务 ID 号的.
$ tsp -c
bin
jenkins
ts-out.gPuqD3
ts-out.YvWAxv

-l选项, 列出队列的情况.
$ tsp -l
ID State E-Level Times [run=0/1] Command &>Output
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]

多执行几次tsp, 加上我们的命令,

$ tsp -l
ID State E-Level Times [run=1/1] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
3 queued ? ? [buildfarm][sleep 30 &>(file) ]
4 queued ? ? [buildfarm][du /bin /boot /cdrom /home &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp] 这个是执行ls命令
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv] 这个是执行ls -l 命令, 后面的 &>/home/buildfarm/ts-out.LK9ofv 只是显示tsp把输出保存到哪个文件里面了,和你的命令没关系的.



-O选项, 大写的o, 设置output保存的文件, 默认是当前路径下面建立个ts-out.类似的临时文件



-D选项,设置 依赖哪个任务, 例如 -D 3, 这个任务执行 需要等待 2号 任务执行结束.
$ tsp -D 3 sleep 33
5 这次依赖3号任务,这次的编号是5.
$ tsp
ID State E-Level Times [run=1/1] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
3 queued ? ? [buildfarm][sleep 30 &>(file) ]
4 queued ? ? [buildfarm][du /bin /boot /cdrom /home &>(file) ]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ] 依赖的前面会多个 && 符合
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]


-S 选项, 设置队列可以同时执行多少个任务, 默认是1个. tsp -S 2 就会设置成2个. 这样2号等待的任务就会开始执行了.
$ tsp
ID State E-Level Times [run=1/1] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
3 queued ? ? [buildfarm][sleep 30 &>(file) ]
4 queued ? ? [buildfarm][du /bin /boot /cdrom /home &>(file) ]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ] 依赖的前面会多个 && 符号
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
$ tsp -S 2 设置并发数为2.
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
3 running ? ? [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
4 queued ? ? [buildfarm][du /bin /boot /cdrom /home &>(file) ]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
设置成2 之后 就发现 有2个任务在执行了. 这个可以根据 服务器的性能 设置.

-K 关闭服务端
$ tsp -K


-k 发送 SIGTERM 信号给某个运行的任务, 也就是结束这个任务的执行. 类似 kill 命令.
$ tsp -k 3 只能kill掉正在running状态的任务. 这个和 -r不太一样的, -r是移除正在 queued 状态的任务.


-C 情况队列中的执行完毕的任务.
$ tsp -C 这样一执行 所有 finished 状态的任务就被删除了.这些完成的任务保存的log文件不会删除的.放完成的任务很多了,队列看着眼花缭乱了,可以清空一下.

-U 可以调整队列前后2个任务的顺序.
$ tsp -U 4-5 这样会调整4和5的执行顺序,

$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
4 running ? ? [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
$ tsp -U 5-6 这样会调整6和5的执行顺序
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
4 running ? ? [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
调整之后,6号任务排在前面了. 类似插队功能.我们的队列是2个并发的,当2或者4号任务结束了就会执行6号任务了.队列从上到下执行的.
交换只能是 queued 状态的任务.

-r 移除队列中的某个任务.
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
4 running ? ? [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
7 queued ? ? [buildfarm][5-6 &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
$ tsp -r 7 删除7号等待中的任务.
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
4 running ? ? [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
0 finished 0 0.93 [buildfarm][ls &>/home/buildfarm/ts-out.nfj6Lp]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
这样删除只会查看队列就没有7号任务了.

$ tsp a
8
再次往里添加命令就会到8号了.


正在运行的任务不能移除的.要使用-k选项 kill 才行.
$ tsp -r 4 这里想要移除4号任务,就会报错了,上面的队列我们看到4号任务正在执行的.
Error in the request: The job 4 cannot be removed.

使用-k选项移除正在运行的任务.
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
4 running ? ? [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
5 queued ? ? [3]&& [buildfarm][sleep 33 &>(file) ]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
8 queued ? ? [buildfarm][a &>(file) ]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
$ tsp -k 4 使用-k选项移除正在运行的任务.
$ tsp
ID State E-Level Times [run=2/2] Command &>Output
2 running ? ? [buildfarm][find / &>/home/buildfarm/ts-out.D6euMm]
5 running ? ? [3]&& [buildfarm][sleep 33 &>/home/buildfarm/ts-out.A4eZ7j]
6 queued ? ? [buildfarm][echo 调整顺序 &>(file) ]
8 queued ? ? [buildfarm][a &>(file) ]
1 finished 0 0.01 [buildfarm][ls -l &>/home/buildfarm/ts-out.LK9ofv]
3 finished 0 30.17 [buildfarm][sleep 30 &>/home/buildfarm/ts-out.tdqX6s]
4 finished -1 627.09 [buildfarm][du /work &>/home/buildfarm/ts-out.l4lo5U]
移除之后 4号任务就 finished 状态了,放到了队列的最下面了.



-c, -t 选项 显示任务的输出,类似tail -f 命令
-t [id] "tail -n 10 -f" the output of the job. Last run if not specified.
-c [id] like -t, but shows all the lines. Last run if not specified.


-i选项 显示任务信息, 什么时候开始的,执行了多久了.在队列等待了多久.
$ tsp -i 默认的 -i 后面没有跟上任务号就是产看队列上面的那个的.
Command: find /
Slots required: 1
Enqueue time: Fri Jul 3 16:48:01 2020
Start time: Fri Jul 3 16:48:01 2020
Time running: 1414.853882s 已经运行的时间,这个任务还在执行的.他还没有end time时间,也没退出状态码

$ tsp -i 10 查看任务10的信息,
Command: sleep 100
Slots required: 1
Enqueue time: Fri Jul 3 17:09:50 2020

$ tsp -i 1 查看任务 1 的信息,
Exit status: died with exit code 0
Command: ls -l
Slots required: 1
Enqueue time: Fri Jul 3 16:47:58 2020
Start time: Fri Jul 3 16:47:58 2020
End time: Fri Jul 3 16:47:58 2020 结束时间
Time run: 0.009577s

$ tsp -i 4 查看任务 4 的信息,
Exit status: killed by signal 15 退出状态
Command: du /work
Slots required: 1
Enqueue time: Fri Jul 3 16:48:12 2020 队列中等待了多久
Start time: Fri Jul 3 16:54:27 2020 开始执行的时间
End time: Fri Jul 3 17:04:54 2020 结束执行的时间
Time run: 627.085266s 用时多久

其他参考

1
2
3
4

https://www.linux.com/news/queuing-tasks-batch-execution-task-spooler/