IMHO Apache + PHP is simpler for a newbie programmer, NodeJS is a little harder due to its asynchronous architecture. In few words, Apache manages a request forking a process and assigning it to the request, NodeJS, on the other hand, has an event-driven architecture which allows it to be able to manage concurrent requests with a single main thread called the event loop. The event loop manages all the requests but delegates IO tasks to other threads.
The asynchronous approach could be harder to understand and if not properly managed could generate a mess in the code (the famous callback hell). However, when you start to rule the event loop properly, NodeJS returns back great satisfaction. I advise you to have a look at the async/await syntax if you are not familiar with it.
I have heard and read many times this sentence NodeJS is super fast, so I have decided to test its performance, and I'll show you the results, comparing it with Apache + PHP stack.
The tests consist of a series of calls bombing, raising progressively the concurrency level in order to analyze the behavior of the server.
The requests belong to two categories:
- A simulated IO operation that takes 100ms to complete. For instance, it could be an execution of a query in the database or a call to a rest API.
- A CPU intensive task (compute the prime numbers from 0 to 5000 with a naive algorithm).
The KPI under observation are:
- The number of requests per second successfully managed.
- The time required to manage a request (mean).
- The longest time required to fulfill a request (worst case).
The environment for the test is made up of:
- A Docker container with Apache Benchmark software that represents the client.
- A Docker container with the NodeJS server (v12.14.0).
- A Docker container with the Apache (v2.4.41) + PHP (v7.3.13) server.
- All the Docker images are based on the alpine v3.11 Linux distribution.
- The Docker engine is v19.03.5.
The Docker containers run on my laptop, a MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports) with:
- 1,4 GHz Quad-Core Intel Core i5
- 8 GB 2133 MHz LPDDR3
- SSD 256 GB
- macOS Catalina (v10.15.2)
The Docker images use the official versions of NodeJS and Apache, no tuning is allowed.
The NodeJS runtime is designed very well to manage requests which involved IO operation, thanks to its asynchronous model.
In fact, NodeJS was able to increase the managed requests per second in accordance with the increasing of concurrency level.
In the CPU task, both technologies reached the maximum result with the minimum concurrency level.
Here again, the asynchronous approach shows its strengths.
The response time is almost the same with the lowest concurrency level, but with 250 concurrent requests, NodeJS was five times faster than Apache.
In this scenario is visible the maximum time waited by a user.
Analyzing the results with the maximum concurrency level:
- IO task: NodeJS -> 1.2 sec, Apache -> 7.8 sec
- CPU task: NodeJS -> 2.7 sec Apache -> 13.4 sec
...and the winner is...NodeJS.
Yes, it's true, NodeJS is superfast! Now I have the proof.
For code details have a look here:
A performance benchmark using Apache Benchmark. You need Docker engine to execute tests.
yarn test-node-simulated-io yarn test-node-cpu-intensive
Apache + PHP
yarn test-php-simulated-io yarn test-php-cpu-intensive