Symfony and ReactPHP Series — Chapter 1

Apisearch
4 min readMay 18, 2019

--

Since the new Symfony era started, some years ago, we have enjoyed as a community the simple, complete and fantastic set of components that, Fabien, his team and all the communities around the world have designed for everyone.

As the years passed, the Symfony community has grown so much, and many and many projects around the world have been built on top of this iconic app.php file.

This is a fact I guess almost every single reader of this blog post could agree easily.

But something has changed during these last years. People is always asking for more performance, more integrations, more documentation, and unlike other developers communities like Javascript, PHP community has been staid faithful to the historic frameworks like Symfony, or even the architecture models like the Request -> Response basic one. And don’t missunderstand me. Basic does’nt always mean easy.

This article series is about one of this times where, from my point of view, a framework like Symfony should be able to adapt to new architectures. I will explain you what is a Promise in terms of development, in terms of PHP and in terms of the actual Symfony HTTP Kernel component. We will start from the begining, by using a basic Symfony application with an Nginx as a server, doing some deep benchmarking and checking the pros and the contras of each step done.

The final step will be the analisis of how we could completely work with Promises in our code without having to leave Symfony as a Framework. And I can tell you, right now, that this is possible. Crafting non-blocking applications on top of Symfony components is a reallity right now, and I will help you to understand why this could be the future of PHP applications, and how we can easily make it happen.

Let’s start.

The Symfony HTTP Kernel

You have probably been afraid of the HttpKernel Symfony component since this was released. And I know it because I’ve been as well since I had no choice. And this is because we have the feeling that the complexity of its internals is too big in front of our comprehension capabilities.

What you need to know about the kernel is that, in fact, I could explain it to you in some small tips. What this component does for you?

  • Check and start all the bundles
  • Build the container
  • Handle a request, dispatch some events, call the controller at get the response, dispatch some extra events and return the response.

Of course, as you could imagine, the kernel is much more than that, but in terms of our topic here, the most important part of what this component does is the line of the Request handle.

$response = $kernel->handle($request);

If you go to the app.php file, or an index.php entrypoint file, or wherever your application is started, you will see that, in fact, is what you will find there. Create a new Request, handle it and return the response.

Have you ever thought about the real cost of this action? How much memory and CPU this process needs? Of course, you will need an Apache or an Nginx in front of this architecture to make it work. Think about the fastest one. Let’s say an Nginx + PHP-FPM. How much time and resource would you need to serve 1000 queries with a concurrency of 50 if your application, basically calls an external resource, let’s say an elasticsearch, with a response time of 20ms?

Let’s make it happen.

  • Nginx + PHP7.3-FPM
  • Symfony 4 application + internal ES call ~ 20ms
  • Production environment + Preloaded cache + Disabled debug
  • 1000 requests + concurrency of 50
  • Ubuntu 16.04 + 4 cores + 16Gb RAM

These are the results of ab benchmark.

Percentage of the requests served within a certain time (ms)
50% 232
66% 234
75% 236
80% 281
90% 293
95% 318
98% 362
99% 372
100% 397 (longest request)

That results could seem good results for a project where the performance is not a goal, but 232 as a response time, for example, is not good for a real time search, where more than 100ms including networking roundrip would mean too much for human perception.

In order to understand a little bit these times, we must understand that no matter how good PHP is, where in each request we built, once and again, our kernel instance. Remember that we said previously that building the kernel means a lot of steps before is done? Like creating the container with all service definitions (not the instances, just the receipes about how to build them). And creating the kernel once and again, means that we cannot reuse any service instance between requests, what means recreating classes and dependencies once and again, as well, until the end of times.

This is not performance friendly.

In the second chapter we will check our first alternative to allow our applications to work much faster and efficient. We will say goodby to Nginx or Apache, and we will start working with one single Kernel for all incoming requests.

You can continue to Symfony and ReactPHP Series — Chapter 2

--

--

Apisearch

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