没有不值得去解决的问题,也没有不值得去学习的技术!

After Another CPU Alert: Upgrading Our WordPress ECS From 1 Core 2G to 2 Cores 4G

Figure 8: The actual price difference, 2 Mbps bandwidth, and restart options shown after selecting 2 cores and 4 GiB

作者:

在

Recently, my WordPress server has again been frequently triggering high CPU usage alerts.

This server hosts the Chinese site, English site, and WordPress backend domain simultaneously, with the frontend connected to EdgeOne and Cloudflare respectively. WordPress uses W3 Total Cache for page caching and Redis for object caching.

Previously, I had conducted multiple rounds of troubleshooting and optimization around CDN, W3TC page pre-caching, Redis object caching, and Nginx rules. However, after the persistent CPU alerts reappeared this time, I began to reconsider a question:

Is continuing to invest significant time into optimizing caching and CDN rules still more cost-effective than directly upgrading the server hardware?

After analyzing CloudMonitor, EdgeOne offline logs, and the actual scope of W3TC pre-caching, I ultimately decided to upgrade the Alibaba Cloud ECS from 1 核 2 GiB to 2 核 4 GiB.

This article documents the entire process, from the recurring alerts and request analysis to the final hardware upgrade and verification.

1. The server again frequently triggers CPU alerts

In the alarm history of Alibaba Cloud CloudMonitor, multiple CPU alerts can be seen.

On the evening of August 3, 2026, the server reached 100% twice:

Plaintext
2026-08-03 20:48:01  CPU 100%
2026-08-03 20:51:01  Recovered to 66.59%

2026-08-03 21:02:01  CPU 100%
2026-08-03 21:04:01  Recovered to 63.78%

On the early morning of August 4, 2026, another round of longer-lasting alerts occurred:

Plaintext
2026-08-04 02:20:01  Alert triggered, CPU 78.38%
2026-08-04 02:21:01  Still exceeding threshold, CPU 79.43%
2026-08-04 02:43:01  Recovered to normal, CPU 68.23%

This high CPU load lasted for about 23 minutes, making it a better sample for detailed analysis.

Figure 1: CPU alarm history in Alibaba Cloud CloudMonitor, showing multiple 70% and 95% threshold alerts
Figure 1: CPU alarm history in Alibaba Cloud CloudMonitor, showing multiple 70% and 95% threshold alerts

I then narrowed the monitoring timeframe to 2026 年 8 月 4 日 02:10~02:50.

From the operating system monitoring curve, it can be seen that between 02:10 and 02:42, the CPU stayed in the 75%–100% range for an extended period and frequently hit 100%.

At the same time, the memory usage remained around 60%. While the memory was not immediately exhausted, for a server with only 2 GiB of RAM, the remaining space was no longer ample.

Figure 2: CPU and memory usage curves from 02:10 to 02:50 on August 4, 2026
Figure 2: CPU and memory usage curves from 02:10 to 02:50 on August 4, 2026

2. Initially suspected W3TC was not pre-caching archive pagination

Previously, I had created a joint pre-caching sitemap for W3 Total Cache used by both the Chinese and English sites.

This file reads:

Plaintext
https://www.shuijingwanwq.com/sitemap_index.xml
https://en.shuijingwanwq.com/sitemap_index.xml

It then recursively collects post, page, category, and tag URLs from both sites, allowing W3TC to warm the cache in batches.

After this alert, I began to suspect:

Does the current pre-caching only cover the first page of category, tag, and date archives, while missing subsequent pagination like /page/2/?

The actual inspection results showed:

Plaintext
Total URL count: 6338
URL count containing /page/N/: 0

This proves that the current joint sitemap indeed does not include the following pages:

Plaintext
/page/2/
/page/3/

/category/example/page/2/
/tag/example/page/2/

/2026/08/page/2/

The reason is quite clear: the generation script only recursively reads URLs already present in the Yoast sitemap; it does not calculate how many paginated pages each archive has and generate /page/N/ additionally.

These paginated pages can still be cached normally by W3TC, but they must first be accessed once by a visitor or crawler:

  1. The request reaches the origin server for the first time;
  2. WordPress, PHP, and the database dynamically generate the page;
  3. W3TC saves the generated result as page cache;
  4. Subsequent identical requests can then directly hit the page cache.

If a large number of crawlers集中访问 previously uncached paginated pages, it will increase PHP and database load.

However, this alone is not enough to conclude that the lack of pre-cached pagination is the root cause of this CPU alert.

3. Aligning Alibaba Cloud alert times with EdgeOne logs

After identifying the alert window, I downloaded the offline logs for the same period from EdgeOne.

Alibaba Cloud CloudMonitor uses Beijing time, and the alert occurred during:

Plaintext
2026-08-04 02:10~02:43

The timestamps in EdgeOne offline log filenames use UTC, so I needed to download:

Plaintext
2026-08-03 18:00~18:59 UTC

Which corresponds to the following Beijing time:

Plaintext
2026-08-04 02:00~02:59 UTC+8

EdgeOne generated separate log files for the Chinese mainland availability zone and the global availability zone (excluding the Chinese mainland).

Figure 3: Two logs from 02:00–02:59 on August 4, 2026, in the EdgeOne offline logs page
Figure 3: Two logs from 02:00–02:59 on August 4, 2026, in the EdgeOne offline logs page

After merging and analyzing both logs, I found two distinct types of automated scraping behavior.

4. A single client continuously scraped 1320 HTML pages

Between 02:10:04~02:42:26, a single client IP continuously accessed the website.

Its request characteristics were as follows:

MetricResult
HTML requests1320
Distinct paths1316
EdgeOne MISS1044
Static asset requests0
Max requests per second16
Start time02:10:04
End time02:42:26

This time frame almost perfectly overlaps with the Alibaba Cloud high CPU load curve.

This client used a seemingly ordinary Chrome User-Agent:

Plaintext
Mozilla/5.0 (Windows NT 10.0; Win64; x64)
AppleWebKit/537.36
Chrome/90.0.4430.93 Safari/537.36

But its behavior was clearly not that of a normal browser:

  • Continuously accessed 1316 distinct HTML paths;
  • Made absolutely no requests for CSS, JavaScript, fonts, or images;
  • Concurrently requested multiple pages within the same second;
  • Rapidly traversed posts, categories, tags, and pagination;
  • Shortly after the scraping ended, the server CPU returned to normal.

The composition of the pages it accessed was as follows:

Page TypeRequests
Post detail pages724
Tag first pages242
Tag pagination156
Category first pages78
Category pagination55
Other pages48
Homepage pagination10
Homepage or search4
Date pagination3

Among these, pagination requests totaled 224, accounting for about 17% of all requests from this client.

This indicates that the lack of pre-cached pagination确实会增加部分负载, but even if all /page/N/ were added to pre-caching, this client would still continue to request hundreds of posts, tag pages, and category pages.

Throughout the 02:10~02:43 alert window, this single client:

  • Accounted for about 23.5% of all requests;
  • Accounted for about 46% of all EdgeOne MISSes;
  • Accounted for about 47.1% of the internal processing time recorded by EdgeOne.

Therefore, it was the primary source of external requests during this CPU alert.

5. Concurrent distributed anomalous path scanning

The logs also contained another group of requests uniformly using a Nexus 5 mobile User-Agent:

Plaintext
Mozilla/5.0 (Linux; Android 6.0; Nexus 5 ...)
Chrome/65.0.3325.181 Mobile Safari/537.36

The characteristics of this group of requests within the same alert window were as follows:

MetricResult
Requests260
Client IPs134
Distinct URLs256
EdgeOne MISS260
RefererAll empty

Some requests also constructed very long, highly anomalous paths, such as continuously concatenating multiple categories and historical paths:

Plaintext
/category/web-devel/web-framework/yii/page/14/
http-basics/http/https-tool/httpserver/http-status/...

These addresses are not the result of normal WordPress navigation; they resemble a distributed scanner combining and traversing URLs.

The response time for some MISS requests reached 20–30 seconds. When requests from the primary scraping client temporarily decreased, these distributed requests could still continue to consume PHP-FPM and CPU.

The logs also contained a large number of Sogou crawler requests, but most of them were already cache hits on EdgeOne:

Plaintext
Total Sogou requests: 1686
HIT: 1586
MISS: 74
Dynamic: 26

Therefore, although the Sogou crawler had a high request volume, it was not the main source of the persistent high CPU load on the origin server this time.

6. Why I did not continue to comprehensively add CDN protection rules

After completing the log analysis, I also checked EdgeOne’s current security protection configuration.

The following are currently enabled:

Plaintext
Adaptive rate limiting
Rule level: Adaptive - Loose
Action: JavaScript challenge

However, in the current plan:

  • Intelligent client filtering requires a higher tier;
  • Slow attack protection requires the Enterprise edition;
  • Precise rate limiting has only 1 quota available;
  • Advanced Bot management also requires a service upgrade.
Figure 4: Adaptive rate limiting enabled in EdgeOne and the current action
Figure 4: Adaptive rate limiting enabled in EdgeOne and the current action
Figure 5: EdgeOne precise rate limiting currently has no rules and only 1 available quota
Figure 5: EdgeOne precise rate limiting currently has no rules and only 1 available quota

I could certainly continue to design rules around User-Agent, per-IP request frequency, HTML page scope, and JavaScript challenges.

But there are several practical issues here:

First, the peak of the main scraping client was only a dozen or so requests per second, which is not a traditional high-traffic attack. If the rules are set too broadly, they will not hit the target; if set too strictly, they may affect normal users and search engines.

Second, there are also a large number of distributed requests from different IPs; restricting a single IP cannot completely solve the problem.

Third, adding all category, tag, and date archive pagination to W3TC pre-caching could rapidly expand the joint sitemap from a few thousand URLs to tens of thousands or more. This might not solve the scraping issue, and could instead cause W3TC itself to generate a persistent pre-warming load.

Fourth, the current server itself only has 1 CPU core. Even if the caching and CDN configurations continue to be optimized, whenever a batch of dynamic requests misses the cache, PHP-FPM can still easily max out the single CPU core.

Continuing to optimize certainly still has value, but at this stage, the return on investment has begun to decline.

7. The server itself was already lacking resource headroom

Before the upgrade, this ECS had the following configuration:

Plaintext
Instance type: ecs.n1.small
CPU: 1 vCPU
Memory: 2 GiB
Public bandwidth: 2 Mbps

In the Alibaba Cloud console, daily memory usage had been hovering around 60% for a long time, and CPU frequently triggered 70%, 95%, or even 100% alerts.

Figure 6: Alibaba Cloud ECS instance information before the upgrade, configured with 1 core and 2 GiB
Figure 6: Alibaba Cloud ECS instance information before the upgrade, configured with 1 core and 2 GiB

In addition, I plan to deploy the Go Tour multilingual program site on this server.

Although the Go Tour production environment will not execute user-submitted Go example code on the server itself, it still requires:

  • An independent Go web process;
  • An Nginx reverse proxy;
  • Logging and monitoring;
  • Temporary resources during deployment and updates;
  • Sharing CPU and memory with existing WordPress services.

Under these circumstances, continuing to squeeze WordPress, Nginx, PHP-FPM, Redis, W3TC, and future Go services all onto 1 核 2 GiB presents a fairly obvious risk.

Therefore, I decided to upgrade the hardware first to add basic headroom for the existing websites and subsequent program sites.

8. With a limited budget, ultimately chose 2 cores and 4 GiB

The Alibaba Cloud upgrade page provides several optional instance types, such as:

TypeConfigurationReference price
ecs.n1.medium2 cores 4 GiB188 CNY/month
ecs.n2.medium2 cores 8 GiB294 CNY/month
ecs.sn1.medium2 cores 4 GiB259 CNY/month
ecs.sn2.medium2 cores 8 GiB286 CNY/month
Figure 7: Optional instance types on the Alibaba Cloud ECS upgrade configuration page
Figure 7: Optional instance types on the Alibaba Cloud ECS upgrade configuration page

Compute-optimized and newer instance families have an advantage in CPU stability, but my budget at the time was relatively limited.

After weighing the current load and costs, I ultimately chose:

Plaintext
ecs.n1.medium
2 vCPU
4 GiB
Public bandwidth remains at 2 Mbps

It is still a shared compute type and not an ideal long-term high-performance solution, but compared to the original 1 核 2 GiB:

  • The number of CPU cores has doubled;
  • The memory capacity has doubled;
  • PHP-FPM no longer has to compete with all other services for a single CPU core;
  • Redis and the system file cache have more memory headroom;
  • It can provide basic running space for Go Tour first.

The instance’s expiration time at that point was 2026 年 12 月 4 日.

The 188 元/月 shown in the console is the reference price for the instance type; the actual upgrade only requires paying the price difference between the old and new configurations for the remaining service period.

The actual price difference paid this time was:

Plaintext
441.03 CNY
Figure 8: The actual price difference, 2 Mbps bandwidth, and restart options shown after selecting 2 cores and 4 GiB
Figure 8: The actual price difference, 2 Mbps bandwidth, and restart options shown after selecting 2 cores and 4 GiB

9. Creating a system disk snapshot before the upgrade

Although changing the instance type on Alibaba Cloud ECS generally does not modify the contents of the system disk and data disks, operations in a production environment should still retain a rollback method.

Before confirming the order, I first created a snapshot for the system disk.

Figure 9: System disk snapshot created successfully
Figure 9: System disk snapshot created successfully

This snapshot is primarily intended to handle the following situations:

  • The system fails to boot normally after the instance restarts;
  • Nginx, PHP-FPM, or Redis fail to start;
  • The file system or configurations become abnormal;
  • A rollback to the pre-upgrade state is necessary.

After completing the snapshot, I returned to the upgrade configuration page and selected:

Plaintext
Restart the instance immediately after the configuration change takes effect

After paying and submitting the order, the ECS automatically restarted. The Chinese site, English site, and backend domain were briefly inaccessible during the restart.

A few minutes later, the Alibaba Cloud console showed that the instance was in the “Running” state again.

10. Verifying CPU, memory, and basic services

After the server recovered, I first performed read-only checks:

Bash
date
uptime
nproc
free -h

ps -ef | grep '[n]ginx'
ps -ef | grep '[p]hp-fpm'
ps -ef | grep '[r]edis-server'

ss -lntp | grep -E ':(80|443|6379)\b'

The actual results were as follows:

Plaintext
CPU cores: 2

Total memory: 3.6 GiB
Used: 327 MiB
Available: 3.0 GiB

Swap: 2.0 GiB
Used: 0

The console purchase was for 4 GiB of memory, while Linux shows about 3.6 GiB, which is a normal result after virtualization and system reservations.

Nginx, PHP-FPM, and Redis all started normally:

Plaintext
Nginx: 1 master, 2 workers
PHP-FPM: Running normally
Redis: 127.0.0.1:6379 listening normally

From the number of Nginx workers, it can also be directly seen that the new system has recognized both CPU cores.

11. Verifying the Chinese site, English site, and backend domain

I then checked origin and public access respectively.

Origin request results:

Plaintext
www.shuijingwanwq.com    HTTP 200
en.shuijingwanwq.com     HTTP 200
admin.shuijingwanwq.com  HTTP 200

Public requests also all returned 200:

Plaintext
https://www.shuijingwanwq.com/        HTTP 200
https://en.shuijingwanwq.com/         HTTP 200
https://admin.shuijingwanwq.com/      HTTP 200

The first origin access to the Chinese homepage took about 14.45 seconds, while the English homepage and backend homepage only took about 0.02 seconds.

When I first saw this result, I suspected that the Chinese homepage still had a performance issue.

However, the server had just restarted, and the W3TC page cache had not yet completed its initial generation, so it was necessary to distinguish between:

  • Persistent slow responses;
  • The first cold cache generation after a restart.

12. The Chinese homepage was just slow during the first cold cache generation

I then consecutively requested the Chinese homepage 5 times:

Plaintext
1st time: TTFB 0.014612 seconds, total time 0.015976 seconds
2nd time: TTFB 0.020882 seconds, total time 0.022608 seconds
3rd time: TTFB 0.015257 seconds, total time 0.016543 seconds
4th time: TTFB 0.022701 seconds, total time 0.023968 seconds
5th time: TTFB 0.017219 seconds, total time 0.018834 seconds

The subsequent 5 requests all stabilized at around 0.02 seconds.

The W3 Total Cache marker also appeared at the bottom of the page:

Plaintext
Using object cache Redis
Using page cache Disk: Enhanced
Served from: www.shuijingwanwq.com

At the same time, W3TC had already regenerated the Chinese homepage cache files:

Plaintext
_index_slash_ssl.html
_index_slash_ssl.html_gzip

Therefore, it can be confirmed that:

The ~14-second response for the Chinese homepage the first time was just cold cache generation after the server restart, not a persistent performance anomaly after the upgrade.

Once the cache generation was complete, the origin homepage response returned to about 20 milliseconds.

13. Actual results after the upgrade

This upgrade ultimately accomplished the following changes:

ItemBefore UpgradeAfter Upgrade
CPU1 core2 cores
Memory2 GiB4 GiB
Actual visible memory in Linux~1.8 GiB~3.6 GiB
Public bandwidth2 Mbps2 Mbps
Actual price difference paid—441.03 CNY
Nginx workers12
Chinese siteNormalNormal
English siteNormalNormal
Backend domainNormalNormal
Redis Object CacheNormalNormal
W3TC Page CacheNormalNormal

After the upgrade was completed, I did not immediately adjust:

  • W3TC pre-caching scope;
  • EdgeOne precise rate limiting;
  • Nginx rate limiting rules;
  • PHP-FPM parameters;
  • Redis maximum memory;
  • CDN caching policies.

This avoids having hardware upgrades and software configuration changes occur simultaneously, which would make it impossible to determine later which change actually produced the effect.

14. A hardware upgrade does not mean the scraping problem has disappeared

This upgrade solved the issue of insufficient server resource headroom; it does not mean that automated scraping has disappeared.

If the following reoccur in the future:

  • A large number of EdgeOne MISSes;
  • Concentrated access to posts, categories, and tag pages;
  • Distributed anomalous path scanning;
  • A single client continuously traversing a large number of HTML pages;

The origin server may still experience significant load.

CDN protection, caching policies, and origin rate limiting still hold value.

But with the server having long been running on 1 核 2 GiB and the CPU frequently reaching 100%, relying solely on piling on more caching and rules to squeeze a single-core resource is no longer the most appropriate approach.

The true significance of this upgrade is:

First giving the server basic concurrency and memory headroom, and then continuing to assess which caching, protection, and software optimizations are truly worth the investment.

15. Next step: Evaluating a software stack upgrade

After the hardware upgrade was completed, I also took inventory of the server’s software stack.

The current main versions include:

Plaintext
Alibaba Cloud Linux 3
Nginx 1.24.0
PHP 8.1.19
Redis 7.0.11
WordPress 7.0.2

PHP-FPM currently uses:

Plaintext
pm = ondemand
pm.max_children = 7

OPcache currently allocates:

Plaintext
opcache.memory_consumption = 128M
opcache.max_accelerated_files = 100000

Now that hardware resources have been increased, the next phase will focus on evaluating:

  1. Whether PHP should be upgraded;
  2. How to verify a new PHP version without breaking the existing WordPress, multilingual, and caching environments;
  3. Whether PHP-FPM needs to be adjusted;
  4. Whether OPcache needs more memory;
  5. Whether Nginx and OpenSSL should be upgraded;
  6. Whether Redis still needs adjustments;
  7. How to reserve resources for the subsequent Go Tour program site.

The software compatibility and rollback risks involved in this part are significantly higher than a simple hardware upgrade, so it will be documented separately in the next article.

Summary

This CPU alert initially led me to suspect that W3TC was not pre-caching archive pagination like /page/2/.

Upon inspection, I confirmed that the 6338 URLs in the joint sitemap indeed did not contain any /page/N/, but EdgeOne logs further revealed that the main factors actually causing the alert were:

  • A single client continuously scraping 1320 HTML pages;
  • Of which 1044 were EdgeOne MISSes;
  • Concurrent distributed anomalous path scanning from 134 IPs;
  • Request times highly overlapping with the high CPU load window.

The lack of pre-cached pagination was only an amplifying factor, not the sole cause.

After evaluating the investment required to continue configuring the CDN, expanding W3TC pre-caching, and adding origin rules, I ultimately decided to resolve the most fundamental hardware headroom issue first.

This time, the Alibaba Cloud ECS was upgraded from:

Plaintext
1 core 2 GiB

To:

Plaintext
2 cores 4 GiB

The actual price difference paid was 441.03 元.

After the upgrade was completed:

  • The system correctly recognized both CPU cores;
  • Available memory increased to about 3 GiB;
  • Nginx, PHP-FPM, and Redis are normal;
  • The Chinese site, English site, and backend domain all recovered;
  • After W3TC cold cache generation completed, the Chinese homepage origin response stabilized at around 0.02 seconds.

The hardware upgrade did not replace caching and protection, but it provided more reasonable base resources for the existing WordPress sites and the subsequent Go Tour program site, and means I no longer have to rely on constantly adding complex rules to sustain a single-core server.

系列导航

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系