兩則預防crontab重複執行任務策略
阿新 • • 發佈:2019-02-18
案例分析
前臺非同步上傳檔案到雲端後臺cron
*/10 * * * * /usr/local/bin/php /path/to/upload.php >> /tmp/apkqueue.log
有時候上傳一個檔案到雲端會很耗時,一個cron還沒有跑完,下一個cron又開啟了,並且一個檔案可能被大於一個cron在同時上傳。
如果一個指令碼的執行時間 比cron的間隔大的多的話,系統就會同時存在多個相同指令碼同時執行。再如果指令碼的子任務沒有加鎖的話,那麼會出現同一條資料
被多個cron執行,造成系統資源浪費。解決的辦法就是加鎖控制同一個指令碼在系統中任何時刻只有一個程序執行,通過鎖的粒度可以做到不同的控制。
以下是我知道的兩種策略:
1,執行的指令碼加鎖
lockf,flock
例:
* * * * * /usr/bin/flock -xn /tmp/full_diff.lock -c 'cd /usr/local/www/admin; /usr/local/bin/php upload.php > /dev/null 2>&1'
30 * * * * (/usr/bin/lockf -s -t 0 /tmp/cdn.push.lock /usr/local/bin/php /path/to/upload.php >> /tmp/log 2>&1)
2,在指令碼中加鎖
<?php
$fp = fopen("/tmp/lock.txt" , "w+");
if (flock($fp, LOCK_EX | LOCK_NB)) { // 進行排它型鎖定
run(); //執行任務
flock($fp, LOCK_UN); // 釋放鎖定
} else {
echo "Couldn't lock the file !";
}
fclose($fp);
?>
2,對子任務加鎖(如果有)
mysql的innodb update操作是行鎖的,可以利用這點對子任務加鎖,一條資料代表一個子任務
這樣可以更西粒度的控制一個子任務同一時刻只有一個程序在執行,同時還可以開啟多個程序。
function run($procid=0)//人為標識的程序id
{
$procNum = 10;//假設開10個程序
$data = select(..) from .. where id%$procNum=$procid;
foreach($data as $row){
exec($row);
}
}
function exec($val)
{
//lock
if(model()->lock($val['id'])) //執行一條update table set status='lock' where id=12312 and status='unlock';
return;
...run..
model()->succ($val['id']);
}
crontab
0 * * * * /proc id=0
1 * * * * /proc id=1
2 * * * * /proc id=2
...
9 * * * * /proc id=9