crontab 解决周期内未执行完重复执行(大数据量)

4,073 阅读2分钟

问题

最近在工作中经常会用到定时任务,发现当我们的脚步的执行时间(假设:130s)大于定时任务的设定时间(假设:1分钟)时,定时任务会重复开始执行,即上次的任务还没有执行完,下次的任务的又开始执行。往往执行的脚本里的资源是不允许同时两个脚本同时共享资源,即保证操作的原子性。否则会产生一连串的问题(数据重复计算等等),想想都可怕。

思路

思路很简单,就是给执行脚本或者计划去加锁。差不多有三种方式去做:

  • 利用临时文件

    • 在执行文件的开头先判断是否有一个 test.lock 的文件,如果有 test.lock 文件,则 exit(),如果没有的话,创建 test.lock 文件,然后执行脚本文件,执行完毕删除 test.lock
  • 利用脚本加锁

    • 思路和第一种方式类似,只是不是用文件判断的方式,而是给文件加锁的方式
  • 利用 linux flock 锁机制

    • flock(FreeBSD lockf,CentOS下为 flock),在脚本执行前先检测能否获取某个文件锁,以防止脚本运行冲突

    • 格式

    flock [-sxun][-w #] fd#
    flock [-sxon][-w #] file [-c] command

    • 选项

    -s, --shared: 获得一个共享锁
    -x, --exclusive: 获得一个独占锁
    -u, --unlock: 移除一个锁,脚本执行完会自动丢弃锁
    -n, --nonblock: 如果没有立即获得锁,直接失败而不是等待
    -w, --timeout: 如果没有立即获得锁,等待指定时间
    -o, --close: 在运行命令前关闭文件的描述符号。用于如果命令产生子进程时会不受锁的管控
    -c, --command: 在shell中运行一个单独的命令
    -h, --help 显示帮助
    -V, --version: 显示版本

    • 锁机制

    共享锁:多个进程可以使用同一把锁,常被用作读共享锁
    独占锁:同时只允许一个进程使用,又称排他锁,写锁。

    • 这里我们需要同时只允许一个进程使用,所以使用独占锁。
      修改后的定时任务如下:

      /1 * * * * flock -xn xxx.lock -c 'php /home/xxx.php' >> /home/xxx.log'

    • 完美的解决了我们的问题

总结来看

  • 总体看来,还是用第三种方法比较好,而且也方便。