PHP如何限制定時任務的程序數量
前言
現在的工作中,經常要寫一些指令碼做一些非同步的操作。
一般是大量的資料修改,或者解決部分併發問題。
為了能夠穩定的做好資料處理,一般情況下會用定時指令碼的方式。
那麼問題來了。
可能存在的問題
當我們處理大量資料的時候,指令碼的執行時間可能很長,或者重複處理某條資料(寫錯的程式設計客棧情況下)。
為了避免資料的重複處理、執行指令碼過多導致伺服器壓力過大等問題,我們需要限制指令碼的執行數量。
如何做
思路一
查詢某種標識的程序數量,如果超過一定數量,則直接退出,不處理。
思路二
記錄每次的PID,可以使用 檔案、redis、memcached 等來儲存。
當啟動一個新程序的時候,去查一下這個標識下面有哪些PID,是否還在執行,且與當前標識有關係。
當超過一定數量的時候,直接退出,不處理。
實踐
思路一實踐
這裡通過 linux 的 ps、grep程式設計客棧、wc 的命令來獲取指定標識的執行程序數。
<?php /** * 是否可以執行 * * @param string $ident 標識 * @param integer $maxNum 最大執行數量 * * @return bool */ function canRun($ident,$maxNum) { $cmd = sprintf('ps ax | grep %s | grep -v /bin/sh | grep -v grep | wc -l',$ident); $fp = @popen($cmd,'r'); $num = (int)trim(@fread($fp,2096)); @pclose($fp); return $num <= $maxNum;ZOfeF}
思路二實踐
這裡使用 redis 儲存 pid 資訊。
通過 /proc/{pid}/cmdline 檔案檢測指定程序是否還在執行。
<?php /** * 檢查 pid 是否存活 * * @param string $pid PID * @param string $ident 標識 * * @return bool */ function isSurvive($pid,$ident) { // 獲取指定pid的cmdline檔案 $cmdlinePath = sprintf('/proc/%s/cmdline',$pid); if (!is_file($cmdlinePath)) { return false; } $cmdline = trim(file_get_contents($cmdlinePath)); // 檢查標識是否在 cmdline 中 return strpos($cmdline,$ident) !== false; } /** * 是否可以執行 * * @param string $ident 標識 * @param integer $maxNum 最大執行數量 * * @return bool */ function canRun($ident,$maxNum) { // 假設已經連結上 $redisHandler = getRedis(); // 定義一個key $key = sprintf('php:job:%s:pid',$ident); // 當前的PID $currentPid = getmypid(); // 將當前的PID寫入redis $redis->sAdd($key,$currentPid); // 獲取redis中的所有pid $pids = $redis->sMembers($key); // 遍歷pid,檢查是否有效 foreach ($pids as $index => $pid) { if ($currentPid == $pid) { continue; } // 檢查 pid 是否還在執行中 if (isSurvive($pid,$ident)) { continue; } // 若不再執行,則直接刪除 unset($pids[$index]); $redis->sRemove($key,$pid); } return count($pids) <= $maxNum; }
關於標識
關於標識,可能我們在執行一些定時指令碼的時候,統一的部分可能就是 php 了;或者,擁有相同標識的指令碼,我們要歸為幾類。
為了能夠實現這些需求,我們可以通過 php 的內建函式 cli_set_process_title 來實現自定義 程式設計客棧COMMAND。
demo.php:
這個時候,我們執行 demo.php,然後通過 ps ax 可以看到如下結果:
程式設計客棧PID USER TIME COMMAND 1 root 0:09 php-fpm: master process (/usr/local/etc/php-fpm.conf) 7 root 0:16 php-fpm: pool www 8 root 0:15 php-fpm: pool www 9 root 0:14 php-fpm: pool www 10 root 0:00 sh 663 root 0:00 sh 690 root 0:00 {php} Job Demo 691 root 0:00 ps ax
修改指定指令碼的程序標題,我們就可以實現定義某些指令碼的標識了。
最後
沒 BUG 的功能,也可能出現 BUG,我們需要更多的思考和設計減少這類錯誤的發生。
到此這篇關於PHP如何限制定時任務程序數量的文章就介紹到這了,更多相關PHP限制程序數量內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!