/** * 让该worker实例开始服务 * * @param bool $is_daemon 告诉 Worker 当前是否运行在 daemon 模式, 非 daemon 模式不拦截 signals * @return void */ public function serve($is_daemon = true) { // 触发该worker进程onServe事件,该进程整个生命周期只触发一次 if ($this->onServe()) { return; } // 安装信号处理函数 if ($is_daemon === true) { $this->installSignal(); } // 初始化事件轮询库 $this->event = new $this->eventLoopName(); // 添加accept事件 $this->event->add($this->mainSocket, BaseEvent::EV_ACCEPT, array($this, 'accept')); // 添加管道可读事件 $this->event->add($this->channel, BaseEvent::EV_READ, array($this, 'dealCmd'), null, 0, 0); // 监听一个udp端口,用来广播ip $error_no = 0; $error_msg = ''; // 创建监听socket $this->udpBroadSocket = @stream_socket_server('udp://0.0.0.0:' . PHPServerConfig::get('workers.' . $this->serviceName . '.port'), $error_no, $error_msg, STREAM_SERVER_BIND); if ($this->udpBroadSocket) { $this->event->add($this->udpBroadSocket, BaseEvent::EV_ACCEPT, array($this, 'recvBroadcastUdp')); } // 主体循环 $ret = $this->event->loop(); $this->notice("evet->loop returned " . var_export($ret, true)); exit(self::EXIT_UNEXPECT_CODE); }
/** * 该worker进程开始服务的时候会触发一次 * @return bool */ protected function onServe() { $this->eventLoopName = 'Select'; $time_interval = PHPServerConfig::get('workers.' . $this->serviceName . '.time_interval_ms'); if ($time_interval > 1) { $this->timeIntervalMS = $time_interval; } $this->installSignal(); $this->event = new $this->eventLoopName(); // 添加管道可读事件 $this->event->add($this->channel, BaseEvent::EV_READ, array($this, 'dealCmd'), 0, 0); // 增加select超时事件 $this->event->add(0, Select::EV_SELECT_TIMEOUT, array($this, 'onTime'), array(), $this->timeIntervalMS); $bootstrap = PHPServerConfig::get('workers.' . $this->serviceName . '.bootstrap'); if (is_file($bootstrap)) { require_once $bootstrap; } if (function_exists('on_start')) { call_user_func('on_start'); } $this->lastCallOnTime = microtime(true); // 主体循环 while (1) { $ret = $this->event->loop(); $this->notice("evet->loop returned " . var_export($ret, true)); } }
/** * 该worker进程开始服务的时候会触发一次 * @return bool */ protected function onServe() { // 文件更新相关 mac不支持inotify 用这个进程监控 500ms检测一次 if (!Inotify::isSuport() && PHPServerConfig::get('ENV') == 'dev') { $this->eventLoopName = 'Select'; // 安装信号处理函数 $this->installSignal(); $this->event = new $this->eventLoopName(); if ($this->protocol == 'udp') { // 添加读udp事件 $this->event->add($this->mainSocket, BaseEvent::EV_ACCEPT, array($this, 'recvUdp')); } else { // 添加accept事件 $this->event->add($this->mainSocket, BaseEvent::EV_ACCEPT, array($this, 'accept')); } // 添加管道可读事件 $this->event->add($this->channel, BaseEvent::EV_READ, array($this, 'dealCmd'), 0, 0); // 增加select超时事件 $this->event->add(0, Select::EV_SELECT_TIMEOUT, array($this, 'checkFilesModify'), array(), 500); // 主体循环 while (1) { $ret = $this->event->loop(); $this->notice("evet->loop returned " . var_export($ret, true)); } return true; } }
public function onServe() { require_once SERVER_BASE . 'thirdparty/MNLogger/MNLogger.php'; $logdir = PHPServerConfig::get('monitor_log_path') ? PHPServerConfig::get('monitor_log_path') : '/home/logs/monitor'; $config = array('on' => true, 'app' => 'php-rpc-server', 'logdir' => $logdir); try { self::$rpcMNLogger = @thirdparty\MNLogger\MNLogger::instance($config); } catch (Exception $e) { } // 初始化统计上报地址 $report_address = PHPServerConfig::get('workers.' . $this->serviceName . '.report_address'); if ($report_address) { StatisticClient::config(array('report_address' => $report_address)); } else { if ($config = PHPServerConfig::get('workers.StatisticWorker')) { if (!isset($config['ip'])) { $config['ip'] = '127.0.0.1'; } StatisticClient::config(array('report_address' => 'udp://' . $config['ip'] . ':' . $config['port'])); } } // 业务引导程序bootstrap初始化(没有则忽略) $bootstrap = PHPServerConfig::get('workers.' . $this->serviceName . '.bootstrap'); if (is_file($bootstrap)) { require_once $bootstrap; } // 服务名 self::$appName = $this->serviceName; }
protected function process($data) { if (!class_exists('Core\\Lib\\RpcServer')) { $frameworkBootstrap = PHPServerConfig::get('workers.' . $this->serviceName . '.framework.path') . '/Serverroot/Autoload.php'; require_once $frameworkBootstrap; } StatisticHelper::tick(); $rpcServer = new Core\Lib\RpcServer(); $ctx = $rpcServer->run($data); StatisticHelper::report($data, $ctx, $this->getRemoteIp()); $this->send($ctx); }
/** * 上报包含文件到监控进程 * @param array $files */ public static function reportIncludedFiles($worker_files_map) { //非开发环境或者安装了inotify扩展直接返回 if (PHPServerConfig::get('ENV') !== 'dev' || Inotify::isSuport()) { return; } if ($worker_files_map && is_array($worker_files_map)) { $files = array(); foreach ($worker_files_map as $worker_name => $files_array) { foreach ($files_array as $file) { $files[$file] = $file; } } if ($files) { return self::sendData(self::CMD_TELL_INCLUDE_FILES, array_values($files)); } } }
/** * 处理数据流. * * @param string $recv_str 接收到的数据流. * * @throws Exception 抛出开发时错误. * * @return void */ public function dealProcess($recv_str) { try { if (($data = Text::decode($recv_str)) === false) { throw new Exception('RpcWorker: You want to check the RPC protocol.'); } if ($data['command'] === 'TEST' && $data['data'] === 'PING') { $this->send('PONG'); return; } $this->rpcCompressor = null; if (strpos($data['command'], 'RPC:') === 0) { $this->rpcCompressor = substr($data['command'], strpos($data['command'], ':') + 1); } elseif ($data['command'] !== 'RPC') { throw new Exception('RpcWorker: Oops! I am going to do nothing but RPC.'); } $data = $data['data']; if ($this->rpcCompressor === 'GZ') { $data = @gzuncompress($data); } $packet = json_decode($data, true); if ($this->encrypt($packet['data'], PHPServerConfig::get('rpc_secret_key')) !== $packet['signature']) { throw new Exception('RpcWorker: You want to check the RPC secret key, or the packet has broken.'); } $data = json_decode($packet['data'], true); if (empty($data['version']) || $data['version'] !== '1.0') { throw new Exception('RpcWorker: Hmm! We are now expect version 1.0.'); } $prefix = 'RpcClient_'; if (strpos($data['class'], $prefix) !== 0) { throw new Exception(sprintf('RpcWorker: Mmm! RPC class name should be prefix with %s.', $prefix)); } $data['class'] = substr($data['class'], strlen($prefix)); $this->process($data); } catch (Exception $ex) { $this->send(array('exception' => array('class' => get_class($ex), 'message' => $ex->getMessage(), 'code' => $ex->getCode(), 'file' => $ex->getFile(), 'line' => $ex->getLine(), 'traceAsString' => $ex->getTraceAsString()))); } }
public function getService() { $this->thriftServiceArray = array(); $client_config = array(); // 查看thriftWorker配置了哪些服务和ip foreach (PHPServerConfig::get('workers') as $worker_name => $config) { if ((empty($config['worker_class']) || $config['worker_class'] != 'ThriftWorker') && $worker_name != 'ThriftWorker') { continue; } $ip = !empty($config['ip']) ? $config['ip'] : '127.0.0.1'; $address = "{$ip}:{$config['port']}"; $providerNamespace = 'Provider'; if ($provider_dir = PHPServerConfig::get('workers.' . $worker_name . '.provider')) { if (($provider_dir = realpath($provider_dir)) && ($path_array = explode('/', $provider_dir = realpath($provider_dir)))) { $providerNamespace = $path_array[count($path_array) - 1]; } } $handlerNamespace = 'Provider'; if ($handler_dir = PHPServerConfig::get('workers.' . $worker_name . '.handler')) { if (($handler_dir = realpath($handler_dir)) && ($path_array = explode('/', $handler_dir))) { $handlerNamespace = $path_array[count($path_array) - 1]; } } if (!empty($provider_dir)) { foreach (glob($provider_dir . "/*", GLOB_ONLYDIR) as $dir) { foreach (glob($dir . "/*.php") as $php_file) { require_once $php_file; } $tmp_arr = explode("/", $dir); $service_name = array_pop($tmp_arr); if (empty($service_name)) { continue; } if ($handlerNamespace == 'Provider') { $class_name = "\\{$handlerNamespace}\\{$service_name}\\{$service_name}Handler"; $handler_file = $handler_dir . '/' . $service_name . '/' . $service_name . 'Handler.php'; } else { $class_name = "\\{$handlerNamespace}\\{$service_name}"; $handler_file = $handler_dir . '/' . $service_name . '.php'; } if (is_file($handler_file)) { require_once $handler_file; } if (class_exists($class_name)) { $re = new ReflectionClass($class_name); $method_array = $re->getMethods(ReflectionMethod::IS_PUBLIC); $this->thriftServiceArray[$service_name] = array(); foreach ($method_array as $m) { $params_arr = $m->getParameters(); $method_name = $m->name; $params = array(); foreach ($params_arr as $p) { $params[] = $p->name; } $this->thriftServiceArray[$service_name][$method_name] = $params; } $client_config[$service_name] = array('nodes' => array($address), 'provider' => $provider_dir); } } } } ClientForTest::config($client_config); return $this->thriftServiceArray; }
/** * 恢复标准输出(开发环境用) * @return void */ protected static function recoverStdFd() { if (PHPServerConfig::get('ENV') == 'dev') { @ob_end_clean(); } if (!posix_ttyname(STDOUT)) { global $STDOUT, $STDERR; @fclose(STDOUT); @fclose(STDERR); $STDOUT = fopen('/dev/null', "rw+"); $STDERR = fopen('/dev/null', "rw+"); return; } }
/** * 进程启动时的一些初始化 * @see PHPServerWorker::onServe() */ public function onServe() { // 初始化thrift生成文件存放目录 $provider_dir = PHPServerConfig::get('workers.' . $this->serviceName . '.provider'); if ($provider_dir) { if ($this->providerDir = realpath($provider_dir)) { if ($path_array = explode('/', $this->providerDir)) { $this->providerNamespace = $path_array[count($path_array) - 1]; } } else { $this->providerDir = $provider_dir; $this->notice('provider_dir ' . $provider_dir . ' not exsits'); } } // 初始化thrift生成类业务实现存放目录 $handler_dir = PHPServerConfig::get('workers.' . $this->serviceName . '.handler'); if ($handler_dir) { if ($this->handlerDir = realpath($handler_dir)) { if ($path_array = explode('/', $this->handlerDir)) { $this->handlerNamespace = $path_array[count($path_array) - 1]; } } else { $this->handlerDir = $handler_dir; $this->notice('handler_dir' . $handler_dir . ' not exsits'); } } else { $this->handlerDir = $provider_dir; } // 统一日志类初始化 require_once SERVER_BASE . 'thirdparty/MNLogger/MNLogger.php'; $logdir = PHPServerConfig::get('monitor_log_path') ? PHPServerConfig::get('monitor_log_path') : '/home/logs/monitor'; $config = array('on' => true, 'app' => 'php-rpc-server', 'logdir' => $logdir); try { self::$rpcMNLogger = @thirdparty\MNLogger\MNLogger::instance($config); } catch (Exception $e) { } // 初始化统计上报地址 $report_address = PHPServerConfig::get('workers.' . $this->serviceName . '.report_address'); if ($report_address) { StatisticClient::config(array('report_address' => $report_address)); } else { if ($config = PHPServerConfig::get('workers.StatisticWorker')) { if (!isset($config['ip'])) { $config['ip'] = '127.0.0.1'; } StatisticClient::config(array('report_address' => 'udp://' . $config['ip'] . ':' . $config['port'])); } } // 业务引导程序bootstrap初始化(没有则忽略) $bootstrap = PHPServerConfig::get('workers.' . $this->serviceName . '.bootstrap'); if (is_file($bootstrap)) { require_once $bootstrap; } // 服务名 self::$appName = $this->serviceName; }
/** * 获取本地ip,优先获取JumeiWorker配置的ip * @param string $worker_name * @return string */ public function getIp($worker_name = 'JumeiWorker') { $ip = $this->getLocalIp(); if (empty($ip) || $ip == '0.0.0.0' || ($ip = '127.0.0.1')) { if ($worker_name) { $ip = PHPServerConfig::get('workers.' . $worker_name . '.ip'); } if (empty($ip) || $ip == '0.0.0.0' || ($ip = '127.0.0.1')) { $ret_string = shell_exec('ifconfig'); if (preg_match("/:(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})/", $ret_string, $match)) { $ip = $match[1]; } } } return $ip; }
protected function getStasticLog($module, $interface, $start_time, $end_time = '', $code = '', $msg = '', $pointer = '', $count = 10) { $pack = new JMProtocol(); $pack->header['cmd'] = self::CMD_PROVIDER; $pack->header['sub_cmd'] = self::SUB_CMD_GET_LOGS; $ip_list = !empty($_GET['ip']) && is_array($_GET['ip']) ? $_GET['ip'] : $this->phpServerIpList; $pointer_list = !empty($_GET['pointer']) && is_array($_GET['pointer']) ? $_GET['pointer'] : array(); $port = PHPServerConfig::get('workers.StatisticProvider.port'); $request_buffer_array = array(); foreach ($ip_list as $key => $ip) { $pointer = isset($pointer_list[$key]) ? $pointer_list[$key] : 0; $pack->body = json_encode(array('module' => $module, 'interface' => $interface, 'start_time' => $start_time, 'end_time' => $end_time, 'code' => $code, 'msg' => $msg, 'pointer' => $pointer, 'count' => $count)); $request_buffer_array["{$ip}:{$port}"] = $pack->getBuffer(); } $read_buffer_array = $this->multiRequest($request_buffer_array); ksort($read_buffer_array); foreach ($read_buffer_array as $address => $buf) { list($ip, $port) = explode(':', $address); $pack = new JMProtocol($buf); $body_data = json_decode($pack->body, true); $log_data = isset($body_data['data']) ? $body_data['data'] : ''; $point = isset($body_data['pointer']) ? $body_data['pointer'] : 0; $read_buffer_array[$address] = array('pointer' => $point, 'data' => $log_data); } return $read_buffer_array; }
protected function getAddress() { $address_array = array(); foreach (PHPServerConfig::get('workers') as $service_name => $config) { if (!empty($config['worker_class']) && ($config['worker_class'] == 'JumeiWorker' || $config['worker_class'] == 'JmTextWorker') || $service_name == 'JumeiWorker' || $service_name == 'JmTextWorker') { $ip = '127.0.0.1'; $address_array["{$ip}:{$config['port']}"] = "{$ip}:{$config['port']} {$service_name}"; } } return empty($address_array) ? $address_array = array('127.0.0.1:2201' => '127.0.0.1:2201 JumeiWorker') : $address_array; }