当前位置:首页 > PHP教程 > php高级应用 > 列表

PHP如何限制定时任务的进程数量

发布:smiling 来源: PHP粉丝网  添加日期:2022-04-19 08:52:33 浏览: 评论:0 

这篇文章主要给大家介绍了关于PHP如何限制定时任务进程数量的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

前言

现在的工作中,经常要写一些脚本做一些异步的操作。

一般是大量的数据修改,或者解决部分并发问题。

为了能够稳定的做好数据处理,一般情况下会用定时脚本的方式。

那么问题来了。

可能存在的问题

当我们处理大量数据的时候,脚本的执行时间可能很长,或者重复处理某条数据(写错的情况下)。

为了避免数据的重复处理、运行脚本过多导致服务器压力过大等问题,我们需要限制脚本的运行数量。

如何做

思路一

查询某种标识的进程数量,如果超过一定数量,则直接退出,不处理。

思路二

记录每次的PID,可以使用 文件、redis、memcached 等来存储。

当启动一个新进程的时候,去查一下这个标识下面有哪些PID,是否还在运行,且与当前标识有关系。

当超过一定数量的时候,直接退出,不处理。

实践

思路一实践

这里通过 linux 的 ps、grep、wc 的命令来获取指定标识的运行进程数。

  1. <?php 
  2. /** 
  3.  * 是否可以运行 
  4.  * 
  5.  * @param string $ident 标识 
  6.  * @param integer $maxNum 最大运行数量 
  7.  * 
  8.  * @return bool 
  9.  */ 
  10. function canRun($ident, $maxNum) 
  11. { 
  12.   $cmd = sprintf('ps ax | grep %s | grep -v /bin/sh | grep -v grep | wc -l', $ident); 
  13.   $fp = @popen($cmd, 'r'); 
  14.   $num = (int)trim(@fread($fp, 2096)); 
  15.   @pclose($fp); 
  16.   return $num <= $maxNum; 
  17. } 

思路二实践

这里使用 redis 存储 pid 信息。

通过 /proc/{pid}/cmdline 文件检测指定进程是否还在运行。

  1. <?php 
  2. /** 
  3.  * 检查 pid 是否存活 
  4.  * 
  5.  * @param string $pid  PID 
  6.  * @param string $ident 标识 
  7.  * 
  8.  * @return bool 
  9.  */ 
  10. function isSurvive($pid, $ident) 
  11. { 
  12.   // 获取指定pid的cmdline文件 
  13.   $cmdlinePath = sprintf('/proc/%s/cmdline', $pid); 
  14.   if (!is_file($cmdlinePath)) { 
  15.    return false; 
  16.   } 
  17.   $cmdline = trim(file_get_contents($cmdlinePath)); 
  18.   // 检查标识是否在 cmdline 中 
  19.   return strpos($cmdline, $ident) !== false; 
  20. } 
  21.  
  22. /** 
  23.  * 是否可以运行 
  24.  * 
  25.  * @param string $ident 标识 
  26.  * @param integer $maxNum 最大运行数量 
  27.  * 
  28.  * @return bool 
  29.  */ 
  30. function canRun($ident, $maxNum) 
  31. { 
  32.   // 假设已经链接上 
  33.   $redisHandler = getRedis(); 
  34.   // 定义一个key 
  35.   $key = sprintf('php:job:%s:pid', $ident); 
  36.   // 当前的PID 
  37.   $currentPid = getmypid(); 
  38.   // 将当前的PID写入redis 
  39.   $redis->sAdd($key, $currentPid); 
  40.   // 获取redis中的所有pid 
  41.   $pids = $redis->sMembers($key); 
  42.   // 遍历pid,检查是否有效 
  43.   foreach ($pids as $index => $pid) { 
  44.     if ($currentPid == $pid) { 
  45.       continue; 
  46.     } 
  47.     // 检查 pid 是否还在运行中 
  48.     if (isSurvive($pid, $ident)) { 
  49.       continue; 
  50.     } 
  51.     // 若不再运行,则直接删除 
  52.     unset($pids[$index]); 
  53.     $redis->sRemove($key, $pid); 
  54.   } 
  55.   return count($pids) <= $maxNum; 
  56. } 

关于标识

关于标识,可能我们在运行一些定时脚本的时候,统一的部分可能就是 php 了;或者,拥有相同标识的脚本,我们要归为几类。

为了能够实现这些需求,我们可以通过 php 的内置函数 cli_set_process_title 来实现自定义 COMMAND。

demo.php:

这个时候,我们运行 demo.php,然后通过 ps ax 可以看到如下结果:

  1. PID  USER   TIME COMMAND 
  2.   1 root   0:09 php-fpm: master process (/usr/local/etc/php-fpm.conf) 
  3.   7 root   0:16 php-fpm: pool www 
  4.   8 root   0:15 php-fpm: pool www 
  5.   9 root   0:14 php-fpm: pool www 
  6.   10 root   0:00 sh 
  7.  663 root   0:00 sh 
  8.  690 root   0:00 {php} Job Demo 
  9.  691 root   0:00 ps ax 

修改指定脚本的进程标题,我们就可以实现定义某些脚本的标识了。

最后

没 BUG 的功能,也可能出现 BUG,我们需要更多的思考和设计减少这类错误的发生。

Tags: PHP限制定时任务

分享到: