Skip to content

Instantly share code, notes, and snippets.

@f3ath
Last active May 16, 2019 03:40
Show Gist options
  • Save f3ath/71978654a949244646486fb22053e324 to your computer and use it in GitHub Desktop.
Save f3ath/71978654a949244646486fb22053e324 to your computer and use it in GitHub Desktop.
An attempt on translation. Source: https://habr.com/ru/post/451916/

After php 7 got released it became feasible to create long running apps at a relatively low price. Such tools like prooph, broadway, tactician, messenger, solving the most common challenges were made available at the engineers' disposal. But what if we dig a bit deeper.

We're going to tell a story of yet another attempt to reinvent the wheel, another tool to build a pub-sub app.

But first we take a quick glance over the today's major trends in the PHP world and scratch the surface of asynchronous programming.

PHP is meant to die

For a long time php apps have been built according to the request/response flow. It's pretty convenient from the developers' standpoint as we don't have to care about memory leaks and connection management. The requests will run in isolation, the resources will be freed up, the connections (e.g. to the data base) will be closed once the process is finished.

Let's take a simple CRUD Symfony app as an example. There are certain steps to be taken to run a DB query and return a JSON response.

  • Config parsing
  • Containter compilation
  • Request routing
  • Execution
  • Response Rendering

It is not only PHP optimizing the execution (using accelerators), the framework itself also caches aggresively (some tasks will not need to be executed on the next request) and takes advantage of lazy initialization. The [Opcache Preloading] will be available starting from v 7.4 allowing to optimize the app initizliation even further.

Nevertheless it won't be possible to avoid the initialization overhead entirely.

Help PHP survive

The solutions seems quite simple - if restarting the app is too expensive, let's start it once and keep it running while passing it the requests and controlling the execution.

There are two conceptually similar projects in PHP ecosystem: [php-pm] and [RoadRunner], both do the same:

  • Create the supervising master process
  • Create a pool of workers
  • For each request the master picks a worker from pool and pass the request to the worker. The client is kep waiting
  • When the worker finishes, the master sends the response to the client and returns the worker back to the pool

If a worker dies, the master creates a new one and adds it to the pool. We have turned our app into a deamon. The only goal is to substantially increase request processing speed by getting rid of the initialization overhead. This is the most painless way to improve performance, but not the only one.

Note

There's a bunch of examples of "speeding up Laravel N times with ReactPHP" one can find on the internet. It is crucial to distinguish between deamonizing (hence saving time on app bootstrapping) and multitasking. Using php-pm and RoadRunner won't make your code non-blocking. You just save time on initializing. It is by definition incorrect to compare php-pm and RoadRunner with ReactPHP/Amp?Swoole in this regard.

PHP and I/O

By default PHP interacts with I/O in the blocking mode. That is if we run a SQL update, the execution thread will stop and wait for the response from the database. The more operations like this you have, the more time the servers idle. Processing a single request may involve several database queries, log writes. Returning the response itself is also a blocking operation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment