Have you ever asked yourself, how can a plugin be a CPU killer, how to find or solve the CPU killer plugin? Well, first of all, let`s talk about PHP concurrency and CPU power, then we will show you real-life examples why some plugins are just badly coded or as we want to say, they are making the biggest possible performance mistake. If you ask a very high-end developer what are the hardest things in development, the answer will be Caching, Concurrency and Naming.
What is PHP concurrency
PHP concurrency is the number of parallel PHP workers that can be executing in a given time. This is one of the most important factors when we are talking about WordPress scalability, in close relation to the CPU power that no one talks about or get it serious. This is one of the reasons why we just don`t believe in all those WordPress benchmark comparisons found on the internet. On the other hand, every managed WordPress hosting has PHP concurrency limit because we want to provide stable hosting, however, many of the hosting providers are hiding this information, is too low or you will be surprised by an email like Quota exceeded, consider upgrade.
How PHP concurrency works behind the scenes
You can have a maximum of X number of PHP workers executing in a given time, all newer requests will be killed (503 error) or delayed (slower execution or 503 error). Many managed WordPress Cloud providers sell plans with only 2 PHP concurrency, but at least 4 is needed and here is why:
- You are making a backup, means this PHP request need a long time.
- Now let’s say your WordPress cron fires, another PHP request that also needs a long time. At this point, the backup and cron requests (your maximum PHP concurrency) work at the same time and need 10 seconds to finish.
- Every next PHP request will be delayed or killed by returning 503 error. Now imagine you are waiting for the backup status to be updated, but nothing is changing visually. Ofc, the new ajax PHP request for checking the backup status cannot be executed due to PHP concurrency limit. To be even funnier, many of you will think that the backup plugin is not working.
CPU power is very important, as much CPU power your site has, the less time is needed for the parallel PHP requests to be finished. On the other hand, the only reason why caching exists is because of this, Period. Dynamic processing of things is always slow and needs a lot of CPU, memory, disk processing, network or similar. Good, now you know how easy is to hit the PHP concurrency limit as the only one user on your site.
How to find a CPU killer plugin
There are two types of CPU killer plugins, the one is making too many non-cacheable requests, the others often/periodically run a long-running PHP process which uses a lot of CPU power. In any use case, you need to find this kind of plugins and switch to an alternative method, there must be one!
Analyze all HTTP requests made by the browser
We warned one of our new clients that SendinBlue Subscribe Form And WP SMTP is just badly coded plugin that makes non-cacheable HTTP request processed by PHP on every page but he did not get us serious. Here is the original ticket message:
“SendinBlue Subscribe Form And WP SMTP” always send a non-cacheable POST request, the worse thing about the server performance/concurrency and biggest developer mistake. Whine them to make the request using a cacheable GET method OR EVEN BETTER include the content in the HTML, not via POST Ajax request since the result is just some countries with a phone prefix.
To be even funnier, the non-cacheable HTTP response is not used for anything on the website. Checking his CPU usage metrics and PHP processes, we know exactly what`s the problem. Disabling the SendinBlue Subscribe Form And WP SMTP drastically lowered the CPU usage and PHP processes.
Here is what the colors mean:
- 1st green: before getting visitors
- Red: every visitor is requesting a non-cacheable HTTP requests
- 2nd green: after disabling SendinBlue Subscribe Form And WP SMTP plugin
Here is how to analyze all HTTP requests made by the browser. Open Chrome Developer Tools(STRL+SHIFT+I)->Nework tab and review all requests that are not made to a static file like /image.jpg and are not cacheable by Litespeed cache plugin. Usually, the request point to /wp-admin/admin-ajax.php file and response header contains x-litespeed-cache-control header with no-cache value.
Analyze our CPU and Cache metrics
When we receive a ticket regarding 503 error, high CPU usage or slow PHP processing, the first thing we do is checking the CPU & Cache Hit metrics. If the chart metrics looks strange, there is a problem. Here is how a strange CPU or Cache metric looks like:
And here is how a strange Non-cacheable metric looks like:
If the site has high CPU usage generated by a lot of non-cacheable HTTP requests, you can easily analyze the access log files to see what is going on. We used the same method to find bad optimized WooCommerce but that use case wasn’t about CPU killer plugin. Here is what kind of plugins can cause high CPU usage or a lot of PHP concurrency:
- A plugin that scans all your pages, like Broken Link Checker. Alternative: use the access logs with an HTTP analyzer software like SmarterStats or with your favorite text editor.
- Plugins used for analytics, advertising or some counters like WP PostViews. Alternative: Google Analytics or Advertising platforms services.
- Plugins used to serve your optimized or resized images via PHP. Alternative: use online image optimizer like Kraken.
- CRON. It`s hard to say how to fix this as there are many use cases. However, using a cron manager plugin or disabling the internal while enabling only the external cron are the first few things you need to do.
Here`s how an access log looks like.
v1.2 '127.0.0.1' '443' '[12/Jul/2018:09:40:13 +0000]' '/home/5b2d0fe3f911c8149cd0e889/public_html/wp-cron.php' 'POST /wp-admin/admin-ajax.php HTTP/1.1' '200' '278' '-' 'Clostebot/1.0' 'no-cache' '-' 'US'
You need to focus on four parameters, IP address (127.0.0.1), DateTime (12/Jul/2018:09:40:13 +0000), request method & URL (POST /wp-admin/admin-ajax.php) and cache status (no-cache) and find answers to this questions:
- Are most of the non-cacheable requests made against same or similar URL just with a different query string?
- Are the non-cache requests made from a single IP address or multiple IP addresses?
- For what is this request used for?
- Can I use an alternative method or what If I disable the plugin?
What is worst of ‘biggest WordPress performance mistake’?
SendinBlue Subscribe Form And WP SMTP
SendinBlue Subscribe Form And WP SMTP plugin has fixed their issue based on our blog post in version 2.9.3 (Changelog: Fix the issue that request ajax call on every page).
WP-SpamShield – WordPress Anti-Spam Plugin
WP-SpamShield plugin, version 1.9.21 is sending non-cacheable PHP request just to render some JS content instead of generating the JS file when the user changes some of their settings. This also produces their plugin to not be compatible with any WordPress optimization plugin as they use wp_enqueue_script wrong, enqueueing PHP instead of JS file.
WordPress GDRP plugin, version 1.6.4 is just another commercial plugin who is requesting 2 non-cachable requests on every page.
Kingdom – WooCommerce Amazon Affiliates Theme
Another commercial theme, but this one is so terrible that is sending 3 non-cacheable requests.
WP GDPR is just another GDPR cookie plugin, sending non-cacheable request to check if GDPR cookie contest should be shown.
WooBought plugin is sending a non-cacheable request every 5 seconds. If 10 visitors do not close your website, here is how much non-cacheable request you will have in one hour: 3600 / 5 * 10 = 7200.
There many other use cases for high CPU usage WordPress plugins as well as methods to diagnose but it`s not possible to explain everything, however, the above examples are most common. A well-optimized WordPress site with one million unique visitors can use less CPU compared to a badly optimized WooCommerce site with no visitors. Yes, that`s true, the one million visitors website is getting visitors from Facebook, hitting a cached page while search-engine crawlers are crawling add-to-cart pages which are not cacheable.