EasySwoole 服務啓動過程以及主體設計流程源碼解析

EasySwoole 服務啓動過程以及主體設計流程源碼解析

本文主要講解EasySwoole 服務的啓動過程,會經過源碼片斷講解主體的設計流程php

命令啓動

當咱們經過php easyswoole start啓動EasySwoole 服務時,命令真正到達的文件是 easyswoole項目\vendor\easyswoole\easyswoole\bin\easyswoole,命令start執行的總體流程以下圖:html

總體流程

主要方法爲:serverStart($options);,其重要執行代碼以下:node

$conf    = Conf::getInstance();
$inst    = Core::getInstance()->initialize();
$inst->run();
  • 初始化Conf,即Config對象(Config類爲一個單例對象),加載全局配置信息,默認配置Config.php內容以下:
return [
    'SERVER_NAME'=>"EasySwoole",
    'MAIN_SERVER'=>[
        'HOST'=>'0.0.0.0',
        'PORT'=>9501,
        'SERVER_TYPE'=>\EasySwoole\Core\Swoole\ServerManager::TYPE_WEB_SERVER,
        'SOCK_TYPE'=>SWOOLE_TCP,//該配置項當爲SERVER_TYPE值爲TYPE_SERVER時有效
        'RUN_MODEL'=>SWOOLE_PROCESS,
        'SETTING'=>[
            'task_worker_num' => 8, //異步任務進程
            'task_max_request'=>10,
            'max_request'=>5000,//強烈建議設置此配置項
            'worker_num'=>8
        ],
    ],
    'DEBUG'=>true,
    'TEMP_DIR'=>null,//若不配置,則默認框架初始化
    'LOG_DIR'=>null,//若不配置,則默認框架初始化
    'EASY_CACHE'=>[
        'PROCESS_NUM'=>1,//若不但願開啓,則設置爲0
        'PERSISTENT_TIME'=>0//若是須要定時數據落地,請設置對應的時間週期,單位爲秒
    ],
    'CLUSTER'=>[
        'enable'=>false,
        'token'=>null,
        'broadcastAddress'=>['255.255.255.255:9556'],
        'listenAddress'=>'0.0.0.0',
        'listenPort'=>'9556',
        'broadcastTTL'=>5,
        'nodeTimeout'=>10,
        'nodeName'=>'easySwoole',
        'nodeId'=>null
    ]
];
  • 執行入口文件Code.php對象的initialize()方法
  • 執行入口文件Code.php對象的run()方法

ps:此處插入說明一個點,EasySwoole中單例類都複用同一個traitmysql

trait Singleton
{
    private static $instance;

    static function getInstance(...$args)
    {
        if(!isset(self::$instance)){
            self::$instance = new static(...$args);
        }
        return self::$instance;
    }
}

入口文件

Easywechat 真實入口文件爲EasySwoole\Core\Core,上述已經說到命令啓動時,執行了如下代碼:web

Core::getInstance();
$inst = Core::getInstance()->initialize();
$inst->run();

在整個EasySwoole生命週期中,Core對象只會被實例化一次,Code的初始化作了以下操做:sql

public function __construct()
    {
        defined('SWOOLE_VERSION') or define('SWOOLE_VERSION',intval(phpversion('swoole')));
        defined('EASYSWOOLE_ROOT') or define('EASYSWOOLE_ROOT',realpath(getcwd()));
        if(file_exists(EASYSWOOLE_ROOT.'/EasySwooleEvent.php')){
            require_once EASYSWOOLE_ROOT.'/EasySwooleEvent.php'; //引入全局初始化事件類
        }
        $this->sysDirectoryInit(); //設置temp目錄和log目錄,路徑可配置化
    }
  • 定義了全局宏SWOOLE_VERSIONEASYSWOOLE_ROOT
  • 引入了全局初始化事件類EasySwooleEvent.php
  • $this->sysDirectoryInit(); 設置temp目錄和log目錄,路徑可配置化

Core類中的initialize方法:緩存

public function initialize():Core
    {
        Di::getInstance()->set(SysConst::VERSION,'2.1.2');
        Di::getInstance()->set(SysConst::HTTP_CONTROLLER_MAX_DEPTH,3);
        EasySwooleEvent::frameInitialize();
        $this->errorHandle();
        return $this;
    }
  • DI容器注入SysConst::VERSIONSysConst::HTTP_CONTROLLER_MAX_DEPTH 的值
  • 執行全局事件類EasySwooleEvent::frameInitialize();事件
  • $this->errorHandle();註冊系統中的set_error_handler、register_shutdown_function

Core類的run方法爲核心功能:websocket

public function run():void
{
    ServerManager::getInstance()->start();
}
  • 實例化ServerManager類,並執行start() 啓動整個服務

服務管理類 ServerManager

ServerManager是一個單例對象,在整個EasySwoole生命週期中,ServeManager對象只會被實例化一次.
ServeManagerrun 方法幹了下面幾件事:swoole

public function start():void
    {
        $this->createMainServer();
        Cache::getInstance();
        Cluster::getInstance()->run();
        CronTab::getInstance()->run();
        $this->attachListener();
        $this->isStart = true;
        $this->getServer()->start();
    }
  • createMainServer() 建立主服務
  • 初始化緩存服務 cache,添加對應的CacheProcess。(Easyswoole的緩存服務是基於swoole_process的管道通訊,後續會專門解析下系統組件cache的源碼)
  • Cluster集羣模式的註冊 (有興趣的能夠經過連接看看)
  • CronTab 服務開啓,後面說下crontab的使用
  • attachListener事件監聽,子服務多端口監聽
  • $this->getServer()->start(); 調用swoole_server的start方法,正式啓動Easyswoole服務

ServerManager 類的createMainServer()方法:框架

(1)讀取配置,建立對應的swoole_server服務

case self::TYPE_SERVER:{
                $this->mainServer = new \swoole_server($host,$port,$runModel,$sockType);
                break;
            }
            case self::TYPE_WEB_SERVER:{
                $this->mainServer = new \swoole_http_server($host,$port,$runModel,$sockType);
                break;
            }
            case self::TYPE_WEB_SOCKET_SERVER:{
                $this->mainServer = new \swoole_websocket_server($host,$port,$runModel,$sockType);
                break;
            }
            default:{
                Trigger::throwable(new \Exception("unknown server type :{$conf['SERVER_TYPE']}"));
            }
        }

(2)註冊事件,onWorker、onTask、onFinish、onRequest等;還有easySwoole事件mainServerCreate,開發者能夠在mainServerCreate事件設置Crontab 服務等

$register = new EventRegister();//事件容器
        $this->finalHook($register);
        EasySwooleEvent::mainServerCreate($this,$register);
        $events = $register->all();

(3)事件註冊的過程當中,還作了以下操做:實例化對象池。開發者能夠經過配置,在此實例化mysql鏈接池等:

//實例化對象池管理
        PoolManager::getInstance();
        PoolManager::getInstance()->__workerStartHook($workerId);

(4)在onRequest事件中,還執行了EasySwooleEventonRequestafterAction,開發者能夠在此自定義處理代碼,如日誌統一刷出等

EasySwooleEvent::onRequest($request_psr,$response_psr);
         $dispatcher->dispatch($request_psr,$response_psr);
         EasySwooleEvent::afterAction($request_psr,$response_psr);

ServerManagerCache::getInstance() 全局跨進程Cache的註冊:

function __construct()
    {
        $num = intval(Config::getInstance()->getConf("EASY_CACHE.PROCESS_NUM"));
        if($num <= 0){
           return;
        }
        $this->cliTemp = new SplArray();
        //如果在主服務建立,而非單元測試調用
        if(ServerManager::getInstance()->getServer()){
            //建立table用於數據傳遞
            TableManager::getInstance()->add(self::EXCHANGE_TABLE_NAME,[
                'data'=>[
                    'type'=>Table::TYPE_STRING,
                    'size'=>10*1024
                ],
                'microTime'=>[
                    'type'=>Table::TYPE_STRING,
                    'size'=>15
                ]
            ],2048);
            $this->processNum = $num;
            for ($i=0;$i < $num;$i++){
                ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class);
            }
        }
    }

Cache 服務基於 swoole_table 實現全局數據共享和傳遞。

以上是EasySwoole服務啓動過程當中的主體設計,其中包括了各類組件的實例化,如PoolManager(對象池)、cache、CronTab等。

相關文章
相關標籤/搜索