zoukankan      html  css  js  c++  java
  • PHP使用守护进程处理队列

    一.概述

      项目是棋牌,web架构是典型的lnmp,server产生的牌局通过http协议请求webserver,由php分析并持久化到mysql,中间参杂了很多业务逻辑,整个流程耗时平均接近2s。
      这种方式存在以下2个问题
      1.整个流程是同步的,server会一直等待php响应,一旦server处理不慎,会造成server阻塞,玩家无法玩牌。
      2.如果牌局数量较多,会占用较多的php-fpm进程,可能造成php-fpm无法处理其他业务。

    二.改进方式

      后面改由server把牌局数据写到redis队列里,php使用守护进程处理redis队列。
      cron每5分钟运行gamelog.php,gamelog检测牌局队列数量,根据队列的数量动态fork对应的子进程处理牌局业务,当子进程数量有多余的空闲进程,gamelog.php
      会杀掉多余的进程,这种方式参考了php-fpm的dynamic模式,具体实现如下:

    define('LEN', 50);//单进程处理牌局队列长度
    define('PROC_MIN', 2);//最小进程数
    define('PROC_MAX', 5);//最大进程数
    ini_set('memory_limit', '128M');
    umask(002);
    set_time_limit(0);//cli模式非必须
    
    $daemonNum = (int) `ps -ef | grep "gamelog.php" | grep -v grep | awk '$3 == 1 {print $2}' | wc -l`;//当前守护进程数
    $appGameLog = app::gamelog();
    $appRedis = app::redis('log');
    $key = akey::gamelog();
    $len = $appRedis->lSize($key);
    $wokerNum = ceil($len / LEN);//需要的进程数
    ($wokerNum < PROC_MIN) && ($wokerNum = PROC_MIN);
    if($daemonNum < $wokerNum){//守护进程数小于需要开启的进程数
        $procNum = $wokerNum - $daemonNum;
        $procNum = min($procNum, PROC_MAX);
        $procNum = max($procNum, PROC_MIN);
        
        for($p = 1; $p <= $procNum; $p++){
            $pid = pcntl_fork();
            if($pid == 0){
                posix_setsid();
                while(true){
                    $data = $appRedis->rPop($key);
                    //此处处理业务
                }
                exit;
            }else if($pid > 0){
                
            }else{
                exit("fork error");
            }
        }
    }else if($daemonNum > $wokerNum){//进程数过多自行kill
        $pidStr = `ps -ef | grep "gamelog.php" | grep -v grep | awk '$3 == 1 {print $2}'`;
        $aPid = explode(PHP_EOL, $pidStr);
        $wokerNum = max($wokerNum, PROC_MIN);//最少保留PROC_MIN个守护进程
        $killNum = $daemonNum - $wokerNum;
        foreach($aPid as $pid){
            $pid = (int) $pid;
            if($pid <= 0){
                continue;
            }
            if(posix_kill($pid, SIGKILL)){
                if(--$killNum <= 0){
                    break;
                }
            }
        }
    }

    php执行shell命令除了system(),exec(),还可以使用``。
    posix_setsid()函数php手册里只有一句说明 Make the current process a session leader
    posix_setsid对应的unix系统函数是setsid(),当进程调用setsid会产生一个新的会话,而且这个进程将不受终端控制
    之前进程有终端控制也会被解除,所以我们在命令行启动gamelog.php,然后关掉终端不会杀掉gamelog.php产生的子进程

    三.改进后的效果
      1.改进后server写redis队列远比通过http协议请求php快,极大减少了server等待牌局处理的时间。
      2.php-fpm不用处理牌局的请求,改由后台进程处理,释放了php-fpm。

    我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3mj93mrrhoqos

  • 相关阅读:
    spring对java远程调用的简化(二)之Hessian,Burlap
    Get busy living--or get busy dying
    Spring:Bean基本管理
    不工作的日子
    Get busy living--or get busy dying
    Spring:Bean基本管理
    不工作的日子
    LAMP2 Apache安装
    apache httpclient 使用
    mysql随机取表中一条数据
  • 原文地址:https://www.cnblogs.com/gaoqin31/p/9550400.html
Copyright © 2011-2022 走看看