您的位置:首页 > 运维架构 > Shell

bash 下如何限制脚本并发运行的几种方法

2013-09-17 14:49 183 查看
转载一个同事的总结:

运维最常见的一个场景是通过 cron 定时运行某个脚本,有时如果脚本因为某些原因导致长时间卡住(例如没有设置超时,或者后台调用 read 这样的命令) ,则会导致多个任务同时运行。

如何避免同一个脚本同时重复跑就成为一个问题。从目前看,大家经常使用的方法有如下2种。

1、通过 ps -ef | grep urscript.sh |grep -v $$ :这种方式毕竟比较土,而且可能匹配错。例如匹配到 cat urscript.sh 这种命令。

另外对于 su -c <cmd> , sudo su - <user> -c <cmd> , ./<cmd> & , nohup ./<cmd> & 这几种方式,误判的概率基本是 100% 。

通过 sid,pgid, ppid 几个来判断,也是有漏判的可能

2、通过 pid 文件 + ps :是常见的方式,但需要考虑 touch pid 时出现竞争的情况。也就是两个脚本同时运行,同时创建 pid 文件,并同时写入 pid

虽然网上有一种通过 FIFO 管道的方式,不过那个比较复杂,不是很推荐

这2种缺点都比较明显。下面介绍另外2种。

1、通过 mkdir、ln -s 这种无法重复执行的方法。例如在脚本中调用 ln -s 创建一个 urscript.pid.lock -> urscript.pid 。

由于 ln -s 不允许同名的源文件存在,所以如果出现并发,必然有一个 ln -s 失败,这时直接退出就可以

2、通过 flock 命令。这个也是比较推荐的方法 。flock 命令来自 util-linux 包。下面以 flock 为例测试,测试脚本名为 test.sh

引用:#!/bin/bash

(

flock -w 1 200 || { echo "bash [$$] Can't get lock , quit" ; exit 1; }

echo $$ > ./test.out

sleep 3

) 200>/var/lock/test.lock

下面模拟并发,可以看到 pid=9927 的这个shell ,无法抢到锁,所以直接退出,而抢到锁的 9926 这个 shell 则成功地写入文件 test.out

引用:linbobo@ubuntu:~$ flock -x

linbobo@ubuntu:~$ (

> ./test.sh &

> ./test.sh &

> wait

> )

bash [9927] Can't get lock , quit

linbobo@ubuntu:~$ cat test.out

9926

linbobo@ubuntu:~$

如果不想等待,可以直接用 --nonblock 选项

这2中也有缺点,就是产生文件,例如 flcok 如果中途被kill,会导致一段时间内无法再次启动。等一下就自动解开了(大概是10秒钟)。

所以,个人觉得比较好的方法是 flock + pid文件 + ps 三重确认,trap 方式删除 lock 文件也不好,毕竟 -9 这种无法捕捉
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: