资讯专栏INFORMATION COLUMN

EasySwoole 服务启动过程以及主体设计流程源码解析

huayeluoliuhen / 1337人阅读

摘要:以上是服务启动过程中的主体设计,其中包括了各种组件的实例化,如对象池等。

EasySwoole 服务启动过程以及主体设计流程源码解析

本文主要讲解EasySwoole 服务的启动过程,会通过源码片段讲解主体的设计流程

命令启动

当我们通过php easyswoole start启动EasySwoole 服务时,命令真正到达的文件是 easyswoole项目vendoreasyswooleeasyswooleineasyswoole,命令start执行的整体流程如下图:

主要方法为:serverStart($options);,其重要执行代码如下:

$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"=>EasySwooleCoreSwooleServerManager::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中单例类都复用同一个trait

trait Singleton
{
    private static $instance;

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

Easywechat 真实入口文件为EasySwooleCoreCore,上述已经说到命令启动时,执行了以下代码:

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

在整个EasySwoole生命周期中,Core对象只会被实例化一次,Code的初始化做了如下操作:

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方法为核心功能:

public function run():void
{
    ServerManager::getInstance()->start();
}

实例化ServerManager类,并执行start() 启动整个服务

服务管理类 ServerManager

ServerManager是一个单例对象,在整个EasySwoole生命周期中,ServeManager对象只会被实例化一次.
ServeManagerrun 方法干了下面几件事:

    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等。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/28777.html

相关文章

  • Easyswoole 源码学习和个人解析 目录

    摘要:易用稳定,本次想通过对的学习和个人解析,吸收框架的思想和设计知识,加强自己对的认知和理解。当然,笔者能力水平有限,后续的文章如有错误,还请指出和谅解。目录如下后续添加文章都会记录在此服务启动过程以及主体设计流程源码解析 前言 swoole是什么?官网的原话介绍是这样的: Swoole 使用纯 C 语言编写,提供了 PHP 语言的异步多线程服务器,异步 TCP/UDP 网络客户端,异步 ...

    CoXie 评论0 收藏0
  • Swoole难上手?从EasySwoole开始

    摘要:组件提供了很多实用的组件包括控制台组件定时器触发器日志处理等等致谢从下一章开始,我们逐步使用的各项功能并开发一个简单的并发版爬虫系统,感谢你看到这里,希望本文可以帮到你,谢谢 showImg(https://segmentfault.com/img/bVbpts4?w=640&h=160); 前言 我一生的文章都会放在这里,我的博客,我希望每一行代码,每一段文字都能帮助你。https:...

    lavor 评论0 收藏0
  • PHP物联网开发利器之Actor并发模型

    摘要:然而尽管如此,很多人可能都没有思考过,如何优雅的写出自己的物联网服务器。 PHP不适合做物联网服务端吗? 在传统的思维中,经常会有人告诉你,php不适合用来做物联网服务端,让你换java,node,go等其他语言,是的,没错传统意义上的php,确实很难做物联网服务器,因为它实在太蹩脚了,当然,这也不是意味着彻底就不能做。举个例子,当你想实现一个TCP服务器的时候,你可能需要写出原理大约...

    ixlei 评论0 收藏0
  • Spring Security 使用总结

    摘要:暑假的时候在学习了并成功运用到了项目中。这是提供的一个安全权限控制框架,可以根据使用者的需要定制相关的角色身份和身份所具有的权限,完成黑名单操作拦截无权限的操作。用户通过登陆操作获得我们返回的并保存在本地。 暑假的时候在学习了 Spring Security 并成功运用到了项目中。 在实践中摸索出了一套结合 json + jwt(json web token) + Spring Boo...

    zoomdong 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<