Jusene's Blog

flock文件锁

字数统计: 1.8k阅读时长: 7 min
2017/02/22 Share

Shell简介

熟悉Linux系统的都知道SHELL(壳),这是一种可以实现用户与kernel交互式的语言,通常在操作系统中,我们称为命令解释语言,如windows系统下dos,再如Linux下的bash,当然Linux下的shell还有很多,我们可以通过查看/etc/shells来查看这台linux系统支持那些shell,当然bash是绝大多数linux系统默认安装shell,因为它来自GNU计划下编写的shell,现在Mac OS系统下默认也是bash,所以可见bash的强大之处。

bash并发式编程

bash是属于面向对象的编程,属于从头到位描述执行解决问题的思路的编程。

废话不多说,直接上码:

我们的目的是计算从0开始,执行100次循环,每次加1,执行100次并发,那结果应该是100。

1
#!/bin/bash
2
countfile=/tmp/count
3
if ! [ -f $countfile  ]
4
then
5
echo 0 > $countfile
6
fi
7
do_count() {
8
read count < $countfile
9
echo $[++count] > $countfile
10
}
11
for i in `seq 1 100`
12
do
13
do_count &
14
done
15
wait
16
cat $countfile
17
rm $countfile

然而执行结果却每次都不一样…

1
[root@node1 ~]# bash  flock.sh  
2
1
3
[root@node1 ~]# bash  flock.sh
4
1
5
[root@node1 ~]# bash  flock.sh
6
1
7
[root@node1 ~]# bash  flock.sh
8
3
9
[root@node1 ~]# bash  flock.sh
10
9
11
[root@node1 ~]# bash  flock.sh

100次并发,我们都是通过将上一次执行结果写入到一个文件来存储,然而100次并发,都是通过读取这个文件里的数字来进行加1操作,可能得到的结果就是,上一次的操作结果还未写入文件,下一次并发已经开始,他读取的还是n次之前的并发留下结果,并发能力的快慢取决于电脑cpu的快慢,如果按照这个运算结果每次都是1,那说明cpu对于处理100次并发搓搓有余。

然而这不是方法,我们需要引入一种机制,执行100次并发,但必须要等上次操作完成,下次并发才能进行,这时最容易就是对文件加锁,等上一次的锁放开下次的并发的锁加上,这样就可以完成这个流程有序的控制。

flock文件锁

下面介绍一个一个linux命令:

1
flock - Manage locks from shell scripts
2
flock [-sxon] [-w timeout] lockfile [-c] command...
3
flock [-sxon] [-w timeout] lockdir [-c] command...
4
flock [-sxun] [-w timeout] fd
5
-s, --shared:    获得一个共享锁,在定向为某文件的FD上设置共享锁而未释放锁的时间内,其他进程试图在定向为此文件的FD上设置独占锁的请求失败,而其他进程试图在定向为此文件的FD上设置共享锁的请求会成功。  
6
-x, --exclusive: 获得一个独占锁,在定向为某文件的FD上设置独占锁而未释放锁的时间内,其他进程试图在定向为此文件的FD上设置共享锁或独占锁都会失败。只要未设置-s参数,此参数默认被设置。
7
-u, --unlock:    移除一个锁,通常是不需要的,脚本执行完会自动丢弃锁。
8
-n, --nonblock:  如果没有立即获得锁,直接失败而不是等待  
9
-w, --timeout:   如果没有立即获得锁,等待指定时间  
10
-o, --close:     在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控  
11
-c, --command:   在shell中运行一个单独的命令
  • 共享锁演示:
1
我们在node1上设置共享锁,这个锁得等5分钟才解开
2
[root@node1 ~]# flock -s /tmp/lock -c "sleep 300"
3
我们在另一个终端上设置同个共享锁,后面的命令可以直接执行。
4
[root@node1 ~]# flock -s /tmp/lock -c "cat /etc/fstab" 
5
#
6
# /etc/fstab
7
# Created by anaconda on Thu Jan 26 08:57:47 2017
8
#
9
# Accessible filesystems, by reference, are maintained under '/dev/disk'
10
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
11
#
12
/dev/mapper/vg_node1-lv_root /                       ext4    defaults        1 1
13
UUID=b41284cf-58ea-42af-a9dc-6d4d3b39e6bd /boot                   ext4    defaults        1 2
14
/dev/mapper/vg_node1-lv_home /home                   ext4    defaults        1 2
15
/dev/mapper/vg_node1-lv_swap swap                    swap    defaults        0 0
16
tmpfs                   /dev/shm                tmpfs   defaults        0 0
17
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
18
sysfs                   /sys                    sysfs   defaults        0 0
19
proc                    /proc                   proc    defaults        0 0
20
/dev/myvg1/mylv1        /users                  ext4     defaults,acl  0 0
21
我们在同个锁文件上加独占锁,这个将一直等待共享锁解开才可以执行。
22
[root@node1 ~]# flock -x /tmp/lock -c "cat /etc/fstab"
23
我们可以看见在/tmp/下创建了一个lock文件
24
[root@node1 ~]# ll /tmp/lock 
25
-rw-r--r--. 1 root root 0 Feb 20 07:20 /tmp/lock
  • 独占锁演示:
1
默认加的就是独占锁,也可-x 指定独占锁
2
[root@node1 ~]# flock /tmp/lock -c "sleep 300"
3
加另一个独占锁,等待锁解开
4
[root@node1 ~]# flock -x /tmp/lock -c "cat /etc/fstab"
5
加另一个共享锁,等待锁解开
6
[root@node1 ~]# flock -s /tmp/lock -c "cat /etc/fstab"
7
但是一直等待不是好办法,设置-n选项,不堵塞,如果获取不到锁,就直接退出,返回1
8
[root@node1 ~]# flock -xn /tmp/lock -c "cat /etc/fstab"
9
[root@node1 ~]# echo $?
10
1
11
我们还可以设置等待几秒后在退出,等待10秒,如果还是获取不到锁,就退出
12
[root@node1 ~]# flock -xw 10 /tmp/lock -c "cat /etc/fstab"
  • 针对文件描述符的演示
1
#!/bin/bash
2
countfile=/tmp/count
3
if ! [ -f $countfile  ]
4
then
5
echo 0 > $countfile
6
fi
7
do_count() {
8
#以只读的方式打开文件,文件描述符为3
9
exec 3< $countfile
10
#对3号文件描述符添加独占锁
11
flock -x 3
12
读取3号文件描述符内容,并赋值给count变量
13
read -u 3 count
14
echo $[++count] > $countfile
15
#解开文件3号文件描述符
16
flock -u 3
17
#取消文件描述符
18
exec 3>&-
19
}
20
for i in `seq 1 100`
21
do
22
do_count &
23
done
24
wait
25
cat $countfile
26
rm $countfile

我们继续上面脚本问题,运行这个脚本,我们就可以等到我们想要的结果,这样就为整个脚本添加了锁的机制,并为并发控制了流程。

  • flock crontab上的应用

其实flock在crontab上应用的最多,计划任务运行脚本,往往会未等上一个脚本运行完成就开始了下一次的运行,这样不仅耗系统资源,而且可能会造成进程卡死或接口瘫痪的结果,使用flock可以很好的避免这样的情况出现。

1
* * * * * flock -xn /tmp/.lock -c "/usr/local/php/bin/php  testphp"

但是凡是锁,就会出现死锁的形象,进程不释放锁,导致下次的脚本运行无法进行,我们还可以引入超时机制.

1
* * * * * timeout 500 -s SIGINT flock -xn /tmp/.lock -c "/usr/local/php/bin/php  testphp"

如果超过500秒这个进程还是占着这个锁,我们就发送sigint信号,相当于ctrl+c,好了有了锁的机制,还有超时机制,crontab计划任务运行的应该可靠的很多。

CATALOG
  1. 1. Shell简介
  2. 2. bash并发式编程
  3. 3. flock文件锁