Just over a week ago I received a contact form email detailing slow performance issues with a LAMP (Linux, Apache MySQL, PHP) web server. During the audit phase, I found that the server’s load average was pretty idle. However, the website was indeed very slow. Among a slew of other issues and misconfigurations, one aspect of this client’s server performance – through no fault of their own – was the speed, or rather lack thereof, in which PHP processes were being executed by the CPU cores.
Upon further investigation, I found that although the volume of traffic was not enough to activate all 18 cores concurrently, that each CPU core took anywhere from 3 to 10 seconds on average to complete PHP requests. As mentioned, there were other issues with PHP, MySQL, Apache, etc. However, for the purpose of this article we will focus on CPU performance, specifically CPU core speed vs number of cores.
First, before we get to that, let’s look at how PHP uses your web server’s CPU cores. As you may have already noticed, PHP is not designed for multithreading, each page/request is served by one PHP process and each process locks on to only one CPU core. This is also the case when PHP waits for MySQL DB queries to complete. Unlike PHP, MySQL is multithreaded, but that’s another topic.
Basically, this is just the way PHP was designed to work. Now, if your web server has more than one page request at a time this means you’ll have several PHP processes/CPU cores running concurrently. As it pertains to PHP web application performance, your choice of CPU is very important!
With 18 cores on this server not being utilized concurrently and no other hardware blocking/bottleneck, it means that the server’s load average always remained below 18. In fact, during monitoring, no more than 8 – 10 cores were used by PHP concurrently during peak traffic. As such, in addition to other recommendations included in my audit report, the following was also suggested:
You have a lot of CPU cores (18) but the core speed is only 2GHz. Since PHP processes are executed per-core, a VPS with 3+GHz cores would fit your workload MUCH better.
Choosing “faster” CPU cores vs more CPU cores
As mentioned, the server had a total of 18 CPU cores, with a core speed of only 2GHz. It was clear from monitoring, that although PHP requests were slow, the issue was made even worse by the slow CPU core speed. In short, let’s look at two things as simply as we can, to better understand the importance of throughput over capacity in this case. 1) faster CPU cores versus, 2) more/additional CPU cores. The old server’s had CPU specs of 18 CPU cores @ 2GHz and my recommended setup was at least 8 CPU cores @ 3+GHz.
Traffic was relatively low for this server with only up to 8 to 10 cores being used and each request taking anywhere from 3 to 10+ seconds to complete. If it takes a 2GHz processor core nine seconds to process a request, then the same request would be returned in around 6 seconds by a 3GHz processor core. Which in turn, would free-up cpu cores for additional requests at a much faster rate.
Although the concurrent capacity would drop from 18 possible concurrent PHP processes to 8, the server’s max throughput would actually increase by over 30%. The result being improved scaling and a faster end-user experience! Of course, if this server was instead experiencing high load averages (18+), with say 3+GHz cores already installed, then the recommendation would be different. Thankfully, as in this case, a lot of performance gains can be had by first addressing PHP and other related performance mis-configurations before touching hardware.
It makes little sense to pay for 18 slow cores if most are unused. The client is blameless because this is often the result of complaining about slow server/website speed to their web host. But the host, instead of alerting them to the of the lack of hardware performance, simply suggest upgrading the VPS package to more and more so called “powerful” packages which feature additional CPU cores, RAM, disk space, etc. During each of these upgrades, the 2GHz clock speed of the CPU cores remains unchanged and adds absolutely no improvement to server throughput or scaling for the extra money.
Hardware upgrades should be the final step after all other areas of application optimization have been covered. Of course, if you can cache your dynamic application using services such as Varnish, Redis, Cloudflare, etc, then you may be perfectly ok with 2GHz CPU cores. In this article, we’ve touched on one, very specific example of a hardware resource utilization bottleneck.
Checking CPU core speed and number of cores – Linux command line
If you are unsure of your server’s CPU specs. You can quickly check with the following command:
lscpu = CPU specs including Clock speed of cores.
root@vps01 [~]# lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 10 On-line CPU(s) list: 0-9 Thread(s) per core: 1 Core(s) per socket: 10 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 62 Model name: Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz Stepping: 4 CPU MHz: 3499.998 BogoMIPS: 6999.99 Hypervisor vendor: KVM Virtualization type: full L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 12288K NUMA node0 CPU(s): 0-9
For CLI based PHP applications, read here. For the next blog post, I hope to write about one of these topics: hardware selecting/sizing, application bottlenecks or MySQL optimization. Please subscribe to content updates using the email form below.