最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • PHP 限制脚本进程数量

    正文概述 转载于:掘金(imjcw)   2021-03-03   483

    前言

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

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

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

    那么问题来了。

    可能存在的问题

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

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

    如何做

    思路一

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

    思路二

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

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

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

    实践

    思路一实践

    这里通过 linuxpsgrepwc 的命令来获取指定标识的运行进程数。

    <?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;
    }
    

    思路二实践

    这里使用 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:

    <?php
    cli_set_process_title('Job Demo');
    sleep(10);
    

    这个时候,我们运行 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 限制脚本进程数量

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元