Linux - 通过操作文件锁来实现shell script进程单实例

Linux - 通过操作文件锁来实现shell script进程单实例

需求描述

在日常的工作中,经常遇到这样的场景:一个脚本程序,一次只能允许其运行一个实例。
如采集系统指标,传输到日志存储系统。如果脚本同时运行了多个实例,那么可能会导致数据在存储系统中储存了多份重复的(片段)数据。
为了解决这个问题,我们提出了一个需求:这种程序,我们希望在一台服务器上运行时,有且仅有一个实例在运行。

需求分析

由于实例对应的就是程序的(单个或多个)进程,我最初想到的就是判断当前用户是否有command为当前程序名称的进程存在,如果有则直接exit,如果没有则运行。这个也是大家常常使用的一个方法,所以本文不讨论该方法。

另一个方法是通过操作与检测文件锁,来决定是否要运行该程序。

资料查看

使用flock从shell操作锁文件,再加入一些业务逻辑达到效果。
我们查看flock手册:

$ man flock
... snippet ommitted ...

       [ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
              This  is useful boilerplate code for shell scripts.  Put it at the top of the shell script you want to lock and
              it'll automatically lock itself on the first run.  If the env var $FLOCKER is not set to the shell script  that
              is  being  run, then execute flock and grab an exclusive non-blocking lock (using the script itself as the lock
              file) before re-execing itself with the right arguments.  It also sets the FLOCKER env var to the  right  value
              so it doesn't run again.
              
... snippet ommitted ...

这里举了一个列子,如果想实现shell script的进程单实例,可以加上上述那行代码。

代码实现

[thesre@centos8 ~]$ cat flock_test.sh 
#!/bin/bash -f

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

echo "I'm running ..."
sleep 3000

效果验证

[thesre@centos8 ~]$ /home/thesre/flock_test.sh & #运行第一个进程
[1] 15112
[thesre@centos8 ~]$ I'm running ...

[thesre@centos8 ~]$ /home/thesre/flock_test.sh & #运行第二个进程
[2] 15136
[thesre@centos8 ~]$ 
[2]    Exit 1                        /home/thesre/flock_test.sh #第二个进程随即退出
[thesre@centos8 ~]$ jobs #再查看发现仅剩第一次运行的进程
[1]  + Running                       /home/thesre/flock_test.sh

延伸

我们看下运行脚本后,操作文件锁的情况。

[thesre@centos8 ~]$ /home/thesre/flock_test.sh &
[1] 19251
[thesre@centos8 ~]$ I'm running ...

[thesre@centos8 ~]$ lslocks #可以看到是19251进程施加的WRITE锁
COMMAND           PID  TYPE SIZE MODE  M START END PATH
(unknown)         545 FLOCK   0B WRITE 0     0   0 /run
master            985 FLOCK   0B WRITE 0     0   0 /
master            985 FLOCK   0B WRITE 0     0   0 /
atd              1015 POSIX   0B WRITE 0     0   0 /run
crond            8083 FLOCK   0B WRITE 0     0   0 /run
AliSecGuard      8518 FLOCK   0B WRITE 0     0   0 /
assist_daemon   19135 FLOCK   0B WRITE 0     0   0 /
aliyun-service  30874 POSIX   0B WRITE 0     0   0 /
(unknown)        6083 FLOCK   0B WRITE 0     0   0 /
(unknown)        6165 FLOCK   0B WRITE 0     0   0 /
flock           19251 FLOCK 131B WRITE 0     0   0 /home/thesre/flock_test.sh
[thesre@centos8 ~]$ cat /proc/locks | grep 19251 #可以看到这个锁的类型是ADVISORY的WRITE锁,还有这个文件所在的主设备号、次设备号以及inode号。
1: FLOCK  ADVISORY  WRITE 19251 fd:01:1334911 0 EOF
[thesre@centos8 ~]$ 
[thesre@centos8 ~]$ ~/strace_cmd_or_pid.sh /home/thesre/flock_test.sh
Trapped CTRL-C
Log direcotry: /tmp/thesre_2021-08-15_12:42:17
[thesre@centos8 ~]$ cd /tmp/thesre_2021-08-15_12:42:17
[thesre@centos8 thesre_2021-08-15_12:42:17]$ ll
total 168
-rw-r--r-- 1 thesre thesre 43706 Aug 15 12:42 _home_thesre_flock_test.sh.19840
-rw-r--r-- 1 thesre thesre  2639 Aug 15 12:42 _home_thesre_flock_test.sh.19841
-rw-r--r-- 1 thesre thesre  2639 Aug 15 12:42 _home_thesre_flock_test.sh.19842
-rw-r--r-- 1 thesre thesre  2639 Aug 15 12:42 _home_thesre_flock_test.sh.19843
-rw-r--r-- 1 thesre thesre  2639 Aug 15 12:42 _home_thesre_flock_test.sh.19844
-rw-r--r-- 1 thesre thesre  3774 Aug 15 12:42 _home_thesre_flock_test.sh.19845
-rw-r--r-- 1 thesre thesre 73522 Aug 15 12:42 _home_thesre_flock_test.sh.19846
-rw-r--r-- 1 thesre thesre  2577 Aug 15 12:42 _home_thesre_flock_test.sh.19847
-rw-r--r-- 1 thesre thesre  6039 Aug 15 12:42 _home_thesre_flock_test.sh.19848
-rw-r--r-- 1 thesre thesre 17989 Aug 15 12:42 _home_thesre_flock_test.sh.19849
[thesre@centos8 thesre_2021-08-15_12:42:17]$ grep flock\( -r #可以看到flock系统调用尝试锁/home/thesre/flock_test.sh失败。
_home_thesre_flock_test.sh.19840:12:42:17.648474 flock(3</home/thesre/flock_test.sh>, LOCK_EX|LOCK_NB) = -1 EAGAIN (Resource temporarily unavailable) <0.000020>

参考资料

https://github.com/karelzak/util-linux/blob/master/sys-utils/flock.c #flock的源码,感兴趣的同学可以深入研读,主要原理是操作Linux的文件锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王万林 Ben

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值