/** * 处理业务 * @see Worker::dealProcess() */ public function dealProcess($buffer) { $buffer = trim($buffer); $ip = $this->getRemoteIp(); if ($ip != '127.0.0.1' && $buffer == 'status') { \Man\Core\Lib\Log::add("IP:{$ip} {$buffer}"); } // 判断是否认证过 $this->adminAuth[$this->currentDealFd] = !isset($this->adminAuth[$this->currentDealFd]) ? 0 : $this->adminAuth[$this->currentDealFd]; if ($this->adminAuth[$this->currentDealFd] < 3) { if ($buffer != \Man\Core\Lib\Config::get($this->workerName . '.password')) { if (++$this->adminAuth[$this->currentDealFd] >= 3) { $this->sendToClient("Password Incorrect \n"); $this->closeClient($this->currentDealFd); return; } $this->sendToClient("Please Try Again\n"); return; } else { $this->adminAuth[$this->currentDealFd] = time(); $this->sendToClient("Hello Admin \n"); return; } } // 单独停止某个worker进程 if (preg_match("/kill (\\d+)/", $buffer, $match)) { $pid = $match[1]; $this->sendToClient("Kill Pid {$pid}\n"); if (!posix_kill($pid, SIGHUP)) { $this->sendToClient("Pid Not Exsits\n"); } return; } $master_pid = file_get_contents(WORKERMAN_PID_FILE); switch ($buffer) { // 展示统计信息 case 'status': $status = $this->getMasterStatus(); if (empty($status)) { $this->sendToClient("Can not get Master status, Extension sysvshm or sysvmsg may not enabled\n"); return; } $worker_pids = $this->getWorkerPidMap(); $pid_worker_name_map = $this->getPidWorkerMap(); foreach ($worker_pids as $worker_name => $pid_array) { if ($this->maxWorkerNameLength < strlen($worker_name)) { $this->maxWorkerNameLength = strlen($worker_name); } } foreach (\Man\Core\Lib\Config::getAllWorkers() as $worker_name => $config) { if (!isset($config['listen'])) { continue; } if ($this->maxAddressLength < strlen($config['listen'])) { $this->maxAddressLength = strlen($config['listen']); } } $msg_type = $message = 0; // 将过期的消息读出来,清理掉 if (\Man\Core\Master::getQueueId()) { while (@msg_receive(\Man\Core\Master::getQueueId(), self::MSG_TYPE_STATUS, $msg_type, 1000, $message, true, MSG_IPC_NOWAIT)) { } } $loadavg = sys_getloadavg(); $this->sendToClient("---------------------------------------GLOBAL STATUS--------------------------------------------\n"); $this->sendToClient(\Man\Core\Master::NAME . ' version:' . \Man\Core\Master::VERSION . "\n"); $this->sendToClient('start time:' . date('Y-m-d H:i:s', $status['start_time']) . ' run ' . floor((time() - $status['start_time']) / (24 * 60 * 60)) . ' days ' . floor((time() - $status['start_time']) % (24 * 60 * 60) / (60 * 60)) . " hours \n"); $this->sendToClient('load average: ' . implode(", ", $loadavg) . "\n"); $this->sendToClient(count($this->connections) . ' users ' . count($worker_pids) . ' workers ' . count($pid_worker_name_map) . " processes\n"); $this->sendToClient(str_pad('worker_name', $this->maxWorkerNameLength) . " exit_status exit_count\n"); foreach ($worker_pids as $worker_name => $pid_array) { if (isset($status['worker_exit_code'][$worker_name])) { foreach ($status['worker_exit_code'][$worker_name] as $exit_status => $exit_count) { $this->sendToClient(str_pad($worker_name, $this->maxWorkerNameLength) . " " . str_pad($exit_status, 16) . " {$exit_count}\n"); } } else { $this->sendToClient(str_pad($worker_name, $this->maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n"); } } $this->sendToClient("---------------------------------------PROCESS STATUS-------------------------------------------\n"); $this->sendToClient("pid\tmemory " . str_pad(' listening', $this->maxAddressLength) . " timestamp " . str_pad('worker_name', $this->maxWorkerNameLength) . " " . str_pad('total_request', 13) . " " . str_pad('packet_err', 10) . " " . str_pad('thunder_herd', 12) . " " . str_pad('client_close', 12) . " " . str_pad('send_fail', 9) . " " . str_pad('throw_exception', 15) . " suc/total\n"); if (!\Man\Core\Master::getQueueId()) { return; } $time_start = time(); unset($pid_worker_name_map[posix_getpid()]); $total_worker_count = count($pid_worker_name_map); foreach ($pid_worker_name_map as $pid => $worker_name) { posix_kill($pid, SIGUSR1); if ($this->getStatusFromQueue()) { $total_worker_count--; } } while ($total_worker_count > 0) { if ($this->getStatusFromQueue()) { $total_worker_count--; } if (time() - $time_start > 1) { break; } } break; // 停止server // 停止server case 'stop': if ($master_pid) { $this->sendToClient("stoping....\n"); posix_kill($master_pid, SIGINT); } else { $this->sendToClient("Can not get master pid\n"); } break; // 平滑重启server // 平滑重启server case 'reload': $pid_worker_name_map = $this->getPidWorkerMap(); unset($pid_worker_name_map[posix_getpid()]); if ($pid_worker_name_map) { foreach ($pid_worker_name_map as $pid => $item) { posix_kill($pid, SIGHUP); } $this->sendToClient("Restart Workers\n"); } else { if ($master_pid) { posix_kill($master_pid, SIGHUP); $this->sendToClient("Restart Workers\n"); } else { $this->sendToClient("Can not get master pid\n"); } } break; // admin管理员退出 // admin管理员退出 case 'quit': $this->sendToClient("Admin Quit\n"); $this->closeClient($this->currentDealFd); break; case '': break; default: $this->sendToClient("Unkonw CMD \nAvailable CMD:\n status show server status\n stop stop server\n reload graceful restart server\n quit quit and close connection\n kill pid kill the worker process of the pid\n"); } }
/** * 根据配置文件创建Workers * @return void */ protected static function spawnWorkers() { // 生成一定量的worker进程 foreach (Config::getAllWorkers() as $worker_name => $config) { // 初始化 if (empty(self::$workerPidMap[$worker_name])) { self::$workerPidMap[$worker_name] = array(); } while (count(self::$workerPidMap[$worker_name]) < $config['start_workers']) { // 子进程退出 if (self::createOneWorker($worker_name) == 0) { self::notice("Worker exit unexpected"); exit(500); } } } }