crond中使用flock命令的坑-阿里云开发者社区

开发者社区> exinnet> 正文

crond中使用flock命令的坑

简介:
+关注继续查看

现象

需要定期去执行一个PHP脚本,首先想到的是通过crond命令来实现这个功能。但是,在crond的执行过程中发现一个诡异的事情。在crond中的配置如下。


*/1 * * * * root /usr/bin/flock -xn /tmp/test.lock -c '/usr/bin/php /home/hailong/test.php > /tmp/test.tt 2>&1'

脚本只会在第一次成功执行,之后就不会再执行。当删除/tmp/test.lock文件后,PHP脚本又能正常执行了。执行完一次后,就又不能正常执行了。

大家看到,配置文件最后增加了 2>&1。为啥要加2>&1呢?请查看博文《一个echo引起的进程崩溃

另外,细心的朋友也会发现,我们使用了flock命令。使用flock命令是为了防止脚本被并发重复执行。更多控制crond脚本并发重复执行的方法,请查看《解决crond脚本执行并发冲突问题


分析

把crond配置中把flock去掉。如下:


*/1 * * * * root /usr/bin/php /home/hailong/test.php > /tmp/test.tt 2>&1

发现脚本可以正常执行了。那必定是flock的问题。flock作为一个成熟的linux命令,有问题的可能性不大。最大的可能性就是PHP代码中某部分代码和flock冲突。PHP代码如下:


<?php
$f = popen("/home/exfilter restart", "r");
while(!feof($f)) {
    $content = fgets($f, 1024);
    if (strpos($content, "start success") !== false) {
        break;
    }
}
pclose($f);
file_put_contents("/tmp/test.log", date("Y-m-d H:i:s"));
?>

之前说过,只有第一次,flock的锁文件不存在的时候,才能正常执行。当锁文件存在后,就不再正常执行。PHP程序执行完毕后,flock并没有释文件锁。那我们看下,/tmp/test.lock文件是被那个文件所占用。


[hailong@vhost ~]$ sudo /usr/sbin/lsof | grep test.lock
exfilter  29821        root    3r      REG              202,1           0   90439710 /tmp/test.lock
[hailong@vhost ~]$ ps aux | grep 29821
root     29821  0.1  0.2 175224 22596 ?        Ssl  07:46   0:00 /home/exfilter -d
56667    30068  0.0  0.0  69460   852 pts/0    S+   07:49   0:00 grep 29821

可见,test.lock文件正是被PHP程序中popen函数启动的进程所占用。由于,启动的是一个守护进程,进程不退出,锁一直被占用。

解决方法

启用flock命令,改用其他方法。更多方法请查看博文《解决crond脚本执行并发冲突问题

延伸阅读

Linux系统上的文件锁主要分为协同锁(advisory lock)和强制锁(mandatory lock)。在Linux上使用的文件锁大部分为协同锁,而且使用强制锁的时候也要检查系统是否支持强制锁.
协同锁,是用户进程主动申请文件锁,锁才能起作用。比如,A进程已经对文件加了协同锁,如果B进程不去申请锁,而直接对文件进行写操作,也是可以的。
强制锁,是由操作系统内核保证的。不需要用户进程自己去申请。
flock命令使用的就是协同锁。
当一个主进程获取一个文件锁后,fork出的子进程也会获取这个文件锁。


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10052 0
javascript:使用document.getElementById读取数据为空分析
  今天写个网页,想在页面加载onLoad时,动态显示由后台其他程序传来的数据时,用document.getElementById获取控件对象总是为空。但是检查了这个id确实是存在的。在网上查阅一番后才知道了其中的原因。
892 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13865 0
css background-position结合disaply:inline-block使用
$(".icon-a").on('click', function (e) { if ($(this).next().css('display') == "none") { $(this).
543 0
多线程编程学习四(Lock 的使用)
一、前言     本文要介绍使用Java5中 Lock 对象,同样也能实现同步的效果,而且在使用上更加方便、灵活,主要包括 ReentrantLock 类的使用和ReentrantReadWriteLock 类的使用。
814 0
javascript之ProtoBuf在websocket中的使用
因为ProtoBuf的序列化效率和大小都非常好,所以它在网络通信上面应用越来越多;而webosocket也随着web3.0应用越来越广泛,而将这两个结合在一起的也会慢慢形成一种趋势;本人是为了测试自已写的一个C# websocket,所以在web上面结合pb也写了一个js实例: 1.
2032 0
+关注
exinnet
淘宝技术专家
91
文章
70
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载