PHP如何限制定時任務(wù)的進(jìn)程數(shù)量
前言
現(xiàn)在的工作中,經(jīng)常要寫一些腳本做一些異步的操作。
一般是大量的數(shù)據(jù)修改,或者解決部分并發(fā)問題。
為了能夠穩(wěn)定的做好數(shù)據(jù)處理,一般情況下會用定時腳本的方式。
那么問題來了。
可能存在的問題
當(dāng)我們處理大量數(shù)據(jù)的時候,腳本的執(zhí)行時間可能很長,或者重復(fù)處理某條數(shù)據(jù)(寫錯的情況下)。
為了避免數(shù)據(jù)的重復(fù)處理、運行腳本過多導(dǎo)致服務(wù)器壓力過大等問題,我們需要限制腳本的運行數(shù)量。
如何做
思路一
查詢某種標(biāo)識的進(jìn)程數(shù)量,如果超過一定數(shù)量,則直接退出,不處理。
思路二
記錄每次的PID,可以使用 文件、redis、memcached 等來存儲。
當(dāng)啟動一個新進(jìn)程的時候,去查一下這個標(biāo)識下面有哪些PID,是否還在運行,且與當(dāng)前標(biāo)識有關(guān)系。
當(dāng)超過一定數(shù)量的時候,直接退出,不處理。
實踐
思路一實踐
這里通過 linux 的 ps、grep、wc 的命令來獲取指定標(biāo)識的運行進(jìn)程數(shù)。
<?php /** * 是否可以運行 * * @param string $ident 標(biāo)識 * @param integer $maxNum 最大運行數(shù)量 * * @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; }
思路二實踐
這里使用 redis 存儲 pid 信息。
通過 /proc/{pid}/cmdline 文件檢測指定進(jìn)程是否還在運行。
<?php /** * 檢查 pid 是否存活 * * @param string $pid PID * @param string $ident 標(biāo)識 * * @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)); // 檢查標(biāo)識是否在 cmdline 中 return strpos($cmdline, $ident) !== false; } /** * 是否可以運行 * * @param string $ident 標(biāo)識 * @param integer $maxNum 最大運行數(shù)量 * * @return bool */ function canRun($ident, $maxNum) { // 假設(shè)已經(jīng)鏈接上 $redisHandler = getRedis(); // 定義一個key $key = sprintf('php:job:%s:pid', $ident); // 當(dāng)前的PID $currentPid = getmypid(); // 將當(dāng)前的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; }
關(guān)于標(biāo)識
關(guān)于標(biāo)識,可能我們在運行一些定時腳本的時候,統(tǒng)一的部分可能就是 php 了;或者,擁有相同標(biāo)識的腳本,我們要歸為幾類。
為了能夠?qū)崿F(xiàn)這些需求,我們可以通過 php 的內(nèi)置函數(shù) cli_set_process_title 來實現(xiàn)自定義 COMMAND。
demo.php:
這個時候,我們運行 demo.php,然后通過 ps ax 可以看到如下結(jié)果:
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
修改指定腳本的進(jìn)程標(biāo)題,我們就可以實現(xiàn)定義某些腳本的標(biāo)識了。
最后
沒 BUG 的功能,也可能出現(xiàn) BUG,我們需要更多的思考和設(shè)計減少這類錯誤的發(fā)生。
到此這篇關(guān)于PHP如何限制定時任務(wù)進(jìn)程數(shù)量的文章就介紹到這了,更多相關(guān)PHP限制進(jìn)程數(shù)量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
學(xué)習(xí)php設(shè)計模式 php實現(xiàn)策略模式(strategy)
這篇文章主要介紹了php設(shè)計模式中的適配器模式,使用php實現(xiàn)適配器模式,感興趣的小伙伴們可以參考一下2015-12-12PHP使用緩存即時輸出內(nèi)容(output buffering)的方法
這篇文章主要介紹了PHP使用緩存即時輸出內(nèi)容(output buffering)的方法,實例分析了php緩存輸出的相關(guān)使用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08phpmyadmin顯示utf8_general_ci中文亂碼的問題終級篇
自己寫PHP也有一年多了,然后編碼問題卻老是沒有得到好的解決,自己的情況是這樣的,網(wǎng)頁顯示完全正常,在phpmyadmin數(shù)據(jù)庫顯示中文亂碼,不管是簡體還是繁體,只要是中文都是亂碼2013-04-04