https://www.jianshu.com/p/4c0f625d5e11

Swoft is a high threshold Web framework in the PHPer community, not only because the framework itself brings many new concepts and cutting-edge design, but also because Swoft is a Swoole-based framework. Swoole is one of the most expensive tools for learning in the PHPer community, and although Swoft has lowered Swoole’s costs, if you don’t know much about Swoole itself, it’s still hard to avoid falling into a variety of “pits”.

In view of this situation, and in order to reduce the difficulty of reading, the author will adjust the writing idea of the following several mechanisms closely related to Swoole. The positioning of the article will be changed from “helping readers to understand Swoft deeply” to “helping readers to understand Swoft and Swoole”, and the pace of narration will also be slowed down.

Web models for three PHP applications




LNMP and LAMP are the basic Web architectures that most PHPer are most familiar with. Here, the common LNMP is used as an example to describe the components of a common Swoole free application: Nginx acts as a Webservice and PHP-FPM maintains a process pool to run Web projects.

In contrast to older CGI models, PHP-FPM has introduced the concept of process resident, avoiding the overhead of creating and destroying processes and extending loads on each request, but still performing all the processes between PHP RINIT and RSHUTDOWN on each request, including reloading the framework source code and project code once. Resulting in a significant performance waste.

The advantage of this model is that it is simple, mature and stable, and the ease of development that comes with running once and then destroying it is one of the reasons PHP has become so popular. The vast majority of PHP projects on the market are based on variations of this architecture.




Swoole, like PHP-FPM, has its own process management mechanism. However, as code becomes highly resident and programming thinking needs to shift from synchronous to asynchronous, Swoole has a low affinity with traditional PHP-FPm-based Web frameworks, and even if adapted to upgraded older Web frameworks, Swoole does not perform well at present.

Therefore, in this compromise, instead of directly running the original PHP code in Swoole, Swoole is used to build a service, and the system communicates with Swoole through an interface, thus complementation the asynchronous processing capability of Web projects. I call this system, which uses both PHP-FPM and Swoole, a semi-swoole application. Because of its simple access, Swoole is the preferred access scheme for most existing projects.

Although lnMP-with-Swoole model introduces Swoole and asynchronous processing capability, its core is STILL PHP-FPM, which is far from giving full play to Swoole’s real advantages.

Swoole-http-server is a huge change from lnMP-with-Swoole. In this model, nginx is not the only component that acts as WebServer. The application itself also contains a built-in WebServer, but because Swoole Http Server is not a professional Http Server, the processing of Http is not perfect, so it still needs to use Nginx as a static resource Server and reverse generation. Swoole Http Server only handles PHP-related Http traffic.

On the one hand, since Swoole already includes WebServer, it no longer needs to implement the general protocol of CGI or fast-CGI to communicate with WebServer. On the other hand, Swoole has its own process management, so PHP-FPM can be removed directly. For PHP resources,Swoole Http Server in this model is equivalent to nginx and PHP-FPM combined in the traditional model.

By loading resident memory at one time, all processes except onRequest are reused between different requests, which greatly reduces the overhead of each request. Due to the characteristics of asynchronous IO, the throughput of this model is much higher than that of traditional LNMP model. In addition, compared with the independent Swoole service, Swoole embedded in the Web system is more direct and convenient to use and has better support.

What is the relationship between Swoft and Swoole?

  1. Swoole is an asynchronous engine that, at its core, provides PHP with the ability to execute asynchronous IO, along with a set of tools that asynchronous programming might use.
  2. Swoole-http-server is a component of Swoole and a kind of SwooleServer, which provides an HttpServer environment suitable for Swoole to run directly.
  3. Swoft is a modern Web framework that is highly compatible with Swoole and is also a practice of the Swoole-HTTP-Server model mentioned above.

Swoft manages Swoole and Swoole-HTTP-Server in the Web model, shields all kinds of complex operation details of Swoole for developers, and provides developers with routing, MVC, database access and other functional components needed for Web development as a Web framework.

How does Swoft use Swoole?

The core is HttpServerr and RpcServer

The Http server

Swoft directly uses Swoole’s built-in \Swoole\Http\Server, which already handles everything at the Http level. We just need to focus on the application itself, and let’s take a look at some important life cycle points for Http services.

Before starting the swoole

The behavior performed in this stage has several characteristics. 1. Basic bootstrap behavior: such as necessary constant define, composer loader import, configuration read. 2. Need to generate the program global period object shared by all worker/task processes, such as Swoole\Lock,Swoft\Memory\Table creation. 3. During startup, only one operation can be performed in all processes: for example, the preceding Process is started. 4. Basic initialization of the Bean container and the loading of coreBeans required by the project startup process. This involves something more miscellaneous, in order to control the length of the subsequent use of a separate article.

The process most closely related to the Http service is the Worker process (group) in Swoole, where most of the business processing takes place. For each Swoole event, Swoft provides a corresponding Swoole listener (corresponding to the @swoolelistener annotation) as a wrapper around the event mechanism. To understand how Swoft’s HttpServer runs under Swoole we need to focus on two Swoole events: swoole.workerstart and swoole.onRequest.

Swoole workerStart events

The workerStart event occurs when the TaskWorker/Worker process starts and is executed once for each TaskWorker/Worker process. This is a key node because the objects created after the swoole.workerstart callback are global to the process and use memory that belongs to a particular Task/Worker process and is independent of each other. Only parts initialized at this stage or later can be thermally overridden. The underlying key codes of the event are as follows:

Swoft\Bootstrap\Server\ServerTrait.php /** * @param bool $isWorker * @throws \InvalidArgumentException * @throws \ReflectionException */ protected function reloadBean(bool $isWorker) { BeanFactory::reload(); $initApplicationContext = new InitApplicationContext(); $initApplicationContext->init(); if($isWorker && $this->workerLock->trylock() && env('AUTO_REGISTER', false)){ App::trigger(AppEvent::WORKER_START); }}Copy the code

There are three things going on here

  1. Initialize the Bean container:

    In the aboveBeanFactory::reload();Swoft’s Bean container initialization portal, where the scanning of annotations takes place. (Actually, this is not accurate. The actual initialization of the Bean container takes place during the BootStrap phase before Swoole Server starts, but only partiallyswoole.workerStartThe number of beans initialized in the inworkerStartInitializing the Bean container is the basis on which Swoft can hot-update code.
  2. Initializing the application context

    initApplicationContext->init()Swoft event listeners (corresponding to @Listener) are registered to allow users to handle the various hooks of the Swoft application itself. And then trigger aswoft.applicationLoaderEvent through which components load configuration files and register HTTP/RPC routes.
  3. Service registration details are covered in the service Governance section.

Swoole onRequest events

Each HTTP request simply fires the swoole.onRequest event when it arrives. The framework code itself is made up of a large number of process-global objects and a small number of program-global objects, whereas the objects created in onReceive, such as $Request and $Response, are request-lifetime and are reclaimed as the HTTP request ends. The underlying key codes of the event are as follows:

/** * Do dispatcher * * @param array ... $params * @return \Psr\Http\Message\ResponseInterface * @throws \InvalidArgumentException */ public function dispatch(... $params): ResponseInterface { /** * @var RequestInterface $request * @var ResponseInterface $response */ list($request, $response) = $params; try { // before dispatcher $this->beforeDispatch($request, $response); // request middlewares $middlewares = $this->requestMiddleware(); $request = RequestContext::getRequest(); $requestHandler = new RequestHandler($middlewares, $this->handlerAdapter); $response = $requestHandler->handle($request); } catch (\Throwable $throwable) { /* @var ErrorHandler $errorHandler */ $errorHandler = App::getBean(ErrorHandler::class); $response = $errorHandler->handle($throwable); } $this->afterDispatch($response); return $response; }Copy the code
  1. beforeDispatch($request, $response):

    Sets the request context and fires oneswoft.beforeRequestEvents.
  2. RequestHandler->handle($request):

    Perform variousThe middlewareCorresponding to the requestactionFor details, refer to the RPC section. The principle is basically the same.
  3. $afterDispatch($response):

    Collates HTTP response packets and sends them to the clientswoft.resourceRelease(Details are provided in connection pooling) events andswoft.afterRequestThe event

In summary, there are a few things you need to know about these life cycle points:

  1. Swoole’s worker process is where most of your Http service code runs.
  2. Some of the initialization and loading is done before Swoole’s server starts, and some is done beforeSwoole.workerstart Event callbackThe former cannot be hot-loaded but may be shared by multiple processes.
  3. The initialization code is only executed once when the system is started and the Worker/Task process is started, unlike phP-fpm, which is executed once for every request, and unlike phP-Fpm, framework objects are destroyed when the request is returned.
  4. Each request is triggered onceSwoole onRequest eventsThis is where our request-handling code actually runs, and only objects generated in this event are recycled at the end of the request.

The RPC server

The life cycle is basically the same as the Http service. For details, see Swoft source Code Analysis -RPC Function Implementation.

Swoft source analysis series directory: www.jianshu.com/p/2f679e0b4…