首頁 > 軟體

crond指令碼執行並行衝突問題

2020-06-16 17:12:40

在計劃任務中,偶爾會看到重複執行的情況:

例如我們公司的計劃任務舉例:

*/2 * * * * root cd /opt/xxxx/test_S1/html/xxxx/admin; php index.php task testOne >/dev/null 2>&1
*/2 * * * * root cd /opt/xxxx/test_S1/html/xxxx/admin; php index.php task testTwo >/dev/null 2>&1

這是兩分鐘執行一次的任務,並不能保證每次開啟的進程能夠在兩分鐘內絕對的執行完畢關閉,進程一直堆積的話,可能會把系統資源給耗盡,導致系統宕機。

舉例:

新建test.php檔案,程式碼如下:

<?php
sleep(70);
?>

新增計劃任務:

*/1 * * * * root cd /home/ganjincheng;php test.php

等待執行,發生堆積

root     26722  0.0  0.0   9232  1064 ?        Ss   12:05   0:00 /bin/sh -c cd /home/ganjincheng;php test.php
root     26744  0.0  0.0 112304  8840 ?        S    12:05   0:00 php test.php
root     29102  0.0  0.0   9232  1060 ?        Ss   12:06   0:00 /bin/sh -c cd /home/ganjincheng;php test.php
root     29116  0.1  0.0 112304  8840 ?        S    12:06   0:00 php test.php
root     29906  0.0  0.0 103320   904 pts/3    S+   12:06   0:00 grep test.php

解決方案

第一種,程式碼中控制並行

這種方法,就是對程式碼進行改造。增加是否有進程執行的判斷。如下面的程式碼:

<?php  
$lockfile = '/tmp/mytest.lock';  
   
if(file_exists($lockfile)){  
    exit();  
}
file_put_contents($lockfile, date("Y-m-d H:i:s"));
   
sleep(70);
 
unlink($lockfile);  
?>

這種判斷檔案是否不存在的方式,會有一個問題。那就是有可能程式未執行到最後,也就是沒有刪除之前建立的mytest.lock檔案。這會導致,之後程式將不能正常執行。

第二種,資料庫控制並行

可以將第一種方案轉移到redis,memache中,進行鍵值判斷。

如果計劃任務是對資料庫進行存取,那可以進行鎖表操作。偶爾我們也可以利用唯一索引與聯合索引的唯一性來避免重複插入情況

第三種,判斷進程是否存在

舉例:

$fp = popen("ps aux | grep 'test.php' | wc -l", "r");
$proc_num = fgets($fp);
if ($proc_num > 3) { //這裡要注意為什麼進程數要大於3,實際操作一遍你就明白了
    exit;
}
sleep(70);

這種方式有一個弊端,就是ps命令要寫的精確。避免把不是執行test.php指令碼的進程也統計到。如:
我們通過vim開啟test.php檔案。就會導致上面命令誤統計。所以當我們不小心vim開啟test.php檔案的時候,就執行不起來了。

第四種,使用linux的flock命令

讓linux幫我們去判斷啊,flock命令提供了檔案鎖的功能。命令引數如下:

[root@www.linuxidc.com]# flock -h
flock (util-linux-ng 2.17.2)
Usage: flock [-sxun][-w #] fd#
       flock [-sxon][-w #] file [-c] command...
       flock [-sxon][-w #] directory [-c] command...
  -s  --shared     Get a shared lock
  -x  --exclusive  Get an exclusive lock
  -u  --unlock     Remove a lock
  -n  --nonblock   Fail rather than wait
  -w  --timeout    Wait for a limited amount of time
  -o  --close      Close file descriptor before running command
  -c  --command    Run a single command string through the shell
  -h  --help       Display this text
  -V  --version    Display version

設定舉例:

*/1 * * * * root flock -xn /tmp/mytest.lock -c 'php ./test.php'

本文永久更新連結地址http://www.linuxidc.com/Linux/2017-06/144883.htm


IT145.com E-mail:sddin#qq.com