一.概述
項目是棋牌,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
