Symfony and ReactPHP Series — Chapter 3

Apisearch
3 min readMay 18, 2019

--

In the second chapter, we changed the Nginx for a PHP-PM server in order to improve the Kernel usage in our servers, and with 10 servers, we saw that the improvement was considerable. Using 10 workers, we turned the old 232ms to a better 103ms.

ReactPHP Server

Our next step will be a step back. Lets drop PHP-PM and let’s think about one of that workers that PHP-PM was actually managing. Each workers is a simple ReactPHP server built on top of an EventLoop. It uses Promises for the server but continues working with a blocking Symfony Kernel.

In order to help you with this task, Apisearch has already a built in server for this purpose. We will use this server for the next posts, so would be interesting if you know about it.

The implementation is pretty easy. Let’s put a piece of code here about a simple skeleton of the server. This code is not created to work in any file, so don’t copy / paste, because the server is much more than that. This is only to understant what our code does.

$loop = new EventLoop();
$socket = new SocketServer('0.0.0.0:8100', $loop);
$http = new HttpServer(
function (ServerRequestInterface $request) {
return new Promise(function ($resolve) use ($request) {
$sfRequest = toSymfonyRequest($request);
$sfResponse = $kernel->handle($sfRequest);
$response = toHttpResponse($sfResponse);
$resolve($response);
});
}
);

$http->listen($socket);
$loop->run();

In some steps

  • We create a server listening to a port, and attached to an event loop
  • Each incoming request creates a small promise. Once is this promise turn, the symfony request is created from the server one, the kernel handles it, and a new response is created from resulting one
  • The promise, before is fulfilled, sends the content to the user ($resolve callable)

As you can see, we are still using a server based on ReactPHP, what allows us to use one shared kernel, but out code is still 100% synchronous.

The server is so simple to install. You only need to add the dependency in your project and make composer update.

You can add the server as a dependency in your composer.json, and after composer updating, you should see a file called server inside the vendor’s bin folder. You can, then, start your application server by setting the host and the port.

vendor/bin/server 0.0.0.0:8100

As a disclaimer, this basic configuration is thought to be used with Symfony 4. If you use another configuration, please go to the server documentation and take a look about all the possible settings.

Let’s check here the benchmark with the same environment than before.

Percentage of the requests served within a certain time (ms)
50% 749
66% 750
75% 751
80% 752
90% 758
95% 768
98% 770
99% 10587
100% 36465 (longest request)

Oh, mama. What are these numbers? Easy. One thread, one CPU and 0 real concurrency. This server will not be able to compute more than 50 requests per second.

That means that, and in order to understand that numbers, most of the requests have been waiting a lot of time before being processed. The processing time is always 20ms, but the total time from when is requested and when the response is sent, the the aggregation of both times.

Let’s prove that with more servers, the numbers will improve properly. Let’s work with 4 servers (1 per core) and an nginx as a load balancer.

Percentage of the requests served within a certain time (ms)
50% 261
66% 270
75% 272
80% 273
90% 274
95% 275
98% 276
99% 277
100% 296 (longest request)

And with 10 workers

Percentage of the requests served within a certain time (ms)
50% 120
66% 129
75% 131
80% 132
90% 135
95% 144
98% 148
99% 151
100% 155 (longest request)

The reason why this server is not as efficient as the PHP-PM one is that Nginx will make a simple round robin, while PPM uses that available — busy flag system, what turns a little bit non-blocking our application.

So we are finally here, where we wanted to be as a goal, with a ~110ms of response time with 10 ReactPHP balanced servers, and an enourmeous purpose in front of us. Let’s make this number much smaller. Let’s go asynchronous. Let’s discover what Promises are and what are they made for.

You can continue to Symfony and ReactPHP Series — Chapter 4

--

--

Apisearch

An Open Source search engine. Give to your users instant and relevant results of all your data! 🔍💨😁