Crontab 脚本加锁执行(flock命令)

使用 Crontab 执行脚本的时候,尤其是脚本间隔时间段而程序运行时间长的时候,很容易出现上一个时间段的脚本还没运行完,下一个时间段的脚本已经启动开始同步执行了这种情况。而这种情况一方面容易导致数据异常,另一方面同时执行的脚本过多也有可能导致服务器内存占用过多等各种情况。所以,Crontab 执行脚本的时候,有必要加锁执行。而给一个shell脚本加锁,需要使用的就是 flock 命令。

命令简介:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ flock

Usage:
flock [options] <file>|<directory> <command> [<argument>...]
flock [options] <file>|<directory> -c <command>
flock [options] <file descriptor number>

Manage file locks from shell scripts.

Options:
-s, --shared get a shared lock 获得一个共享的锁。
-x, --exclusive get an exclusive lock (default) 获得一个独占的锁。
-u, --unlock remove a lock 移除一个锁,通常是不需要的,脚本执行完后会自动丢弃锁。
-n, --nonblock fail rather than wait 如果没有立即获得锁直接失败而不是等待。
-w, --timeout <secs> wait for a limited amount of time 如果没有立即获得锁就等待指定的时间。
-E, --conflict-exit-code <number> exit code after conflict or timeout
-o, --close close file descriptor before running command 在运行命令前关闭文件的描述符。用于如果命令产生子进程时会不受锁的管控。
-c, --command <command> run a single command string through the shell 在shell中运行一个单独的命令。
--verbose increase verbosity

-h, --help display this help and exit 显示帮助。
-V, --version output version information and exit 显示版本。

For more details see flock(1).

一般格式:

1
2
$ flock -sxun fd#
$ flock -sxon file [-c] command...

如下是网上给到的一个demo

在/home目录下建立一个test.sh。

1
$ vim /home/test.sh

输入:

1
2
#!/bin/bash
wget --limit-rate=200k -P /tmp http://cachefly.cachefly.net/100mb.test

运行一个超过一分钟的命令。

1
$ chmod +x /home/test.sh

编辑crontab:

1
$ crontab -e

输入:

1
*/1 * * * * /usr/bin/flock -xn /var/run/test.lock -c '/home/test.sh'

设置每一分钟执行一次。

重启服务:

1
$ service crond restart

这样只有第一个进程执行完毕后,才会执行当前的下一个进程。在第一个进程执行过程中,下一分钟 crontab 运行 flock 检测到获得不了锁,就直接退出,直到第一个进程执行完,flock 再次获得锁。

注:

1、这种使用文件锁的方式,在linux中非常常见,通过一个pid文件,来避免两个进程同时运行,mysql 和 postgresql 都有 pid 文件,mysql 中只记录了 pid 值,postgresql 的 pid 中除了记录有 pid 值,还有数据目录,pid 文件的创建时间,端口号,监听地址和共享内存的地址。

2、使用PID文件锁还有一个好处,方便进程向自己发停止或者重启信号。Nginx编译时可指定参数

1
--pid-path=/var/run/nginx.pid

进程起来后就会把当前的PID写入这个文件,当然如果这个文件已经存在了,也就是前一个进程还没有退出,那么Nginx就不会重新启动。进程管理工具 Supervisord 也是通过记录进程的PID来停止或者拉起它监控的进程的

3、flock 加的 advisory lock,也就是建议性锁,巧合的是,postgresql 中也有 advisory lock,非常适用于秒杀等高并发的场景。flock是通过获取文件的fd来加锁的。