使用 Crontab 执行脚本的时候,尤其是脚本间隔时间段而程序运行时间长的时候,很容易出现上一个时间段的脚本还没运行完,下一个时间段的脚本已经启动开始同步执行了这种情况。而这种情况一方面容易导致数据异常,另一方面同时执行的脚本过多也有可能导致服务器内存占用过多等各种情况。所以,Crontab 执行脚本的时候,有必要加锁执行。而给一个shell脚本加锁,需要使用的就是 flock
命令。
命令简介:
1 | flock |
一般格式:
1 | flock -sxun fd# |
如下是网上给到的一个demo
在/home目录下建立一个test.sh。
1 | vim /home/test.sh |
输入:
1 | !/bin/bash |
运行一个超过一分钟的命令。
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来加锁的。