網站突然變慢、後台轉圈圈轉到天荒地老,甚至收到主機商一封「您的帳號資源使用超標」的通知信——這幾乎都指向同一件事:主機 CPU 過高。問題在於,「CPU 飆高」只是症狀,真正麻煩的是怎麼從一堆程序裡揪出肇事的那一個。是流量暴增?某支外掛在背景狂跑?還是 wp-cron 自己把自己累死?
這篇用一條清楚的排查路線,帶你從主機整體狀態看起,用 top 鎖定吃 CPU 的程序,再一路追到 WordPress 內部,確認到底是哪支外掛或哪段排程在肇事。有 SSH 權限的 VPS 使用者、和只能登 cPanel 的共享主機使用者,文中都各有對應的查法。
主機 CPU 過高在共享主機和 VPS 上是兩件不同的事
先釐清一個常被混為一談的觀念:你看到的「CPU 過高」,在不同主機環境下指的不是同一回事。
在 VPS 或獨立主機上,CPU 過高通常是字面意思——實體或虛擬的處理器核心被某些程序佔滿,系統忙不過來,反應變慢。這時你登進去用 top 看,會看到某幾支程序的 %CPU 居高不下。
在共享主機(虛擬主機)上情況不一樣。你跟其他幾十、甚至上百個帳號共用同一台實體機器,主機商會替每個帳號設一個 CPU 配額(常見以「CPU 秒數」或「entry process」「I/O」等指標計算)。你帳號裡的程式只要在單位時間內吃掉太多 CPU,主機商的控制面板就會把你標成超標、開始限流(throttling),網站因此變慢甚至短暫無法連線。換句話說,共享主機的「CPU 過高」往往是相對於你被分配到的那一小塊額度,而不是整台機器真的滿載。
這個差異決定了你的排查工具:VPS 看 top、ps 這類系統指令;共享主機多半沒有 SSH,只能看 cPanel 的資源統計加上 WordPress 內部的診斷工具。下面兩條路都會講到。
動手查之前,先分辨是真滿載還是配額被吃完
排查的第一步不是急著開 top,而是先判斷瓶頸到底在 CPU 計算本身,還是另有其因。有 SSH 的話,先跑這兩個指令拿到全局概況。
第一個看系統負載:
uptime
輸出尾端會有三個數字,分別是過去 1 分鐘、5 分鐘、15 分鐘的平均負載(load average)。這個值大致代表「正在跑、加上排隊等 CPU 的程序數量」。判讀的基準是你的 CPU 核心數:一台 2 核的機器,負載長時間維持在 2 以下算正常,持續高於核心數就代表 CPU 在塞車。如果 1 分鐘的值遠高於 15 分鐘的值,表示問題是剛發生、還在惡化。
第二個看記憶體:
free -h
重點看 available 這一欄是不是過低,以及 Swap 的 used 是不是在長。如果實體記憶體吃緊、開始動用慢得要命的 Swap,系統會被拖到看起來像 CPU 滿載,但根因其實是記憶體不足。先把這條岔路排除掉,免得後面方向抓錯。
確認負載確實偏高、且不是記憶體在搞鬼之後,才進入下一步:找出是哪支程序在吃 CPU。
有 SSH 就用 top,先讀懂 us、sy、wa 三個數字
top 是最直接的即時程序監視工具,但多數人只盯著下半部的程序列表,忽略了上方那行 CPU 摘要——其實那行才是指引方向的羅盤。
執行 top 之後,看 %Cpu(s) 那一列,重點是三個數字:
- us(user,使用者空間):應用程式本身吃掉的 CPU。這項偏高,代表是你跑的程式在算東西,例如 PHP、資料庫、某支腳本。WordPress 站的 CPU 問題九成落在這裡。
- sy(system,核心空間):作業系統核心吃掉的 CPU。這項異常偏高,通常跟大量系統呼叫、行程切換或網路處理有關。
- wa(I/O wait):CPU 在乾等磁碟讀寫的時間。這項很高代表瓶頸根本不在 CPU 算力,而在硬碟太慢或磁碟操作太頻繁——這種時候升級 CPU 一點用都沒有。
在 top 介面按大寫的 P,程序就會依 %CPU 由高到低排序,吃 CPU 最兇的浮在最上面。每一列要記下四個欄位:PID(程序編號)、USER(執行者)、%CPU(CPU 佔用率)、COMMAND(指令或程序名稱)。htop 是 top 的進階版,畫面有顏色、可用滑鼠操作、能以樹狀檢視程序父子關係,沒裝的話用 sudo apt install htop 或 sudo yum install htop 裝起來會順手很多。
讀懂這三個數字,等於先替後面的偵查定了調:us 高就往應用層查(PHP、外掛、資料庫),wa 高就往磁碟和 I/O 查,sy 異常就往連線數、網路請求查。
鎖定吃 CPU 的程序,再往應用層追下去
知道方向之後,要把那支程序的身分釘死。除了 top,ps 指令適合拍一張當下的快照:
ps aux --sort=-%cpu | head -n 15
這會把 CPU 佔用率最高的前 15 支程序列出來。看 COMMAND 與 USER 兩欄,先確認這是什麼東西:是 Web 伺服器的工作程序(如 php-fpm、httpd、nginx)、資料庫(mysqld、mariadbd)、排程腳本,還是一支你根本不認識的可疑程序。
如果是不認識的程序名、CPU 吃滿又怎麼都殺不掉,要提高警覺——這是被植入挖礦程式或惡意程式的典型特徵,後面預防那段會再提。
確認是正常的應用程序(例如 php-fpm 或 mysqld)之後,光知道「PHP 在吃 CPU」還不夠,得再往裡追一層。對 WordPress 站來說,這一層通常落在三個地方:某個慢查詢、某支外掛、或某段排程。
往資料庫追,可以登進 MySQL/MariaDB 下這道指令看當下在跑什麼查詢:
SHOW FULL PROCESSLIST;
如果看到同一類查詢反覆出現、或卡在 locked 狀態,問題就在資料庫層,多半是缺索引或某支外掛寫了爛 SQL。
往 PHP 層追,在 WordPress 內部安裝 Query Monitor 這支外掛,它能逐頁列出每個請求跑了哪些 SQL、各花多少時間、由哪支外掛或主題觸發,是把「PHP 吃 CPU」精準歸因到「哪支外掛的哪段程式」最直接的工具。
WordPress 站最常見的兩個肇事者是 wp-cron 與 admin-ajax
在 WordPress 主機的 CPU 問題裡,有兩支內建程式被點名的次數遠高於其他——wp-cron.php 與 admin-ajax.php。先搞懂它們為什麼會肇事,後面才知道怎麼處理。
wp-cron.php 是 WordPress 的排程機制,負責定時發文、自動備份、外掛的定期掃描等任務。但它有個先天設計:它並不是真正的系統級排程。真正的 Cron 是作業系統層級的服務,時間到就執行,不管有沒有人在看網站。WordPress 身為 PHP 應用通常沒權限去碰系統排程,於是改用一個「模擬」做法——每當有訪客(含搜尋引擎爬蟲)載入任何一個頁面,WordPress 就在背景偷偷觸發一次 wp-cron.php,去檢查有沒有到期的排程要跑。
問題就出在這個觸發模式。低流量網站半夜沒人來,排程就一直躺著不動,造成漏發文章;而高流量網站每一次頁面載入都觸發一次檢查,過於頻繁地執行 wp-cron.php,就會把 CPU 吃高。一個明明沒什麼訪客的站卻長期耗用大量資源,wp-cron 是該優先檢查的項目。
admin-ajax.php 則是 WordPress 處理後台與前台 AJAX 請求的入口,其中一個高頻來源是 Heartbeat API——它讓後台維持即時連線,例如自動儲存草稿、顯示其他人正在編輯的提示。當某支外掛濫用 Heartbeat、或在前台頻繁對 admin-ajax.php 發 POST 請求,這支程式的存取次數就會暴衝,連帶把 CPU 拉高。在主機的流量監控裡如果看到滿滿的 admin-ajax.php 存取紀錄,幾乎都是某支外掛造成的。
這兩支都是 WordPress 正常運作的一部分,不能直接砍掉,要做的是「管理它們的觸發頻率」,方法放在後面處理那段。
怎麼確認是哪支外掛在肇事
把範圍縮到「某支外掛」之後,最可靠的確認方式是二分法停用,配合資源監控觀察前後變化。不要靠感覺猜,也不要一次全停又一次全開——那樣只會知道「停光就好了」,卻抓不出真兇。
務必先在測試環境或非尖峰時段操作,正式站直接停用外掛可能影響到正在瀏覽的訪客。流程是這樣:
第一、把目前啟用中的外掛分成兩半,先停用其中一半。
第二、觀察主機的 CPU 或負載指標,給它幾分鐘到十幾分鐘穩定下來。
第三、如果 CPU 降下來了,代表兇手在剛剛停用的那一半裡;如果沒降,就在另一半。
第四、針對有問題的那一半,再對半停用、再觀察,重複幾輪,範圍會快速收斂到一兩支外掛。
確認嫌疑外掛之後,先別急著刪。先看它有沒有可調的設定能降低資源消耗——很多時候不是外掛壞,而是頻率設定太激進。實務上常見的例子是自動登出閒置使用者這類外掛,把檢查週期從 15 分鐘改成 90 分鐘,主機負擔就明顯下降;又或者某支即時流量統計、失效連結掃描的外掛,把掃描頻率調低就解決了。
還有一個常被忽略的清理點:有些外掛在移除時忘了一併刪掉自己註冊的排程,殘留的孤兒排程會繼續被 wp-cron 觸發。用 WP Crontrol 這支外掛可以看到目前系統裡所有排程事件、各自的執行頻率與下次執行時間,把那些來路不明、或屬於早已移除外掛的排程清掉,也能替 CPU 減壓。
沒有 SSH 的共享主機改用 cPanel 與 WordPress 內部工具
共享主機使用者多半碰不到 top、ps 這些指令,但排查邏輯不變,只是換成手邊有的工具。
第一站是主機控制台。cPanel 通常有「資源使用量」或「CPU and Concurrent Connection Usage」之類的頁面,會顯示你帳號近期的 CPU、記憶體、entry process 使用曲線,以及有沒有觸發限流。先從這裡確認超標是持續性的,還是某個時段的尖峰——持續超標多半是背景排程或爛查詢,週期性尖峰常跟流量或定時任務有關。部分主機商還提供存取紀錄或流量統計,能看到 wp-cron.php、admin-ajax.php 的請求次數,這就是前面說的兩大肇事者的線索。
第二站回到 WordPress 內部。前面提過的 Query Monitor 能在後台逐頁分析 SQL 與外掛耗時,WP Crontrol 能檢視與清理排程,這兩支在共享主機上一樣管用,因為它們跑在 WordPress 應用層,不需要伺服器權限。確認嫌疑外掛的二分法停用流程,在共享主機上也完全照做。
需要設定系統級 Cron Job 來取代 wp-cron 時,cPanel 本身就有「Cron Jobs」選項可以新增,這點下一段會接著講。
找到兇手之後怎麼處理與長期預防
抓到肇事原因後,對應不同的根因有不同的處理方向,以下是幾種常見情境的處理思路。
針對 wp-cron 過於頻繁,標準做法是停用它的訪客觸發,改用穩定的系統排程。先在 wp-config.php 的 /* That's all, stop editing! Happy publishing. */ 這行註解「之上」加入:
define('DISABLE_WP_CRON', true);
務必放在那行註解之前才會生效,且修改前先備份檔案。接著到主機控制台(cPanel、Plesk 或 SSH)的 Cron Jobs 設定一個系統排程,每 5 到 15 分鐘主動去呼叫 wp-cron.php 一次:
wget -q -O - https://your-domain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
把網址換成你自己的網域即可。這樣排程改由作業系統準時調度,既不漏發任務、又不必每次有人開頁面就觸發,CPU 與資料庫負擔都會降下來。
針對 admin-ajax 與 Heartbeat 太頻繁,可裝 Heartbeat Control 類的外掛調整觸發週期或在不需要的頁面停用 Heartbeat API;若請求源頭是某支外掛濫用 AJAX,回到二分法找出來、調設定或換掉。
針對 資料庫慢查詢,開啟慢查詢紀錄、找出反覆出現的爛 SQL,替查詢用到的欄位補上適當索引,這通常是投報率最高的優化。
針對 流量或攻擊,正常流量成長就考慮升級主機規格或加上頁面快取、CDN 分擔靜態資源;若是惡意的 CC 攻擊,則需要 WAF 或流量清洗服務擋在前面。
針對 可疑程序或挖礦程式(多半發生在 VPS),透過 top、ps 鎖定,用 lsof 查它開了哪些檔案與連線,必要時隔離主機網路、跑安全掃描工具清除,並補上被入侵的漏洞、強化密碼與防火牆。
長期預防的核心是把「事後救火」變成「事前看得到」。替主機與網站建立基本監控(CPU、記憶體、負載、磁碟 I/O),設好告警門檻,在剛開始異常時就收到通知;定期更新 WordPress 核心、外掛與主題,因為更新常含效能修正與記憶體洩漏的修補;同時養成在裝外掛前評估它的口碑與資源消耗的習慣,畢竟最省 CPU 的外掛,就是那支你最後沒裝的。
主機 CPU 過高從來不是「重開機就好」的問題,它是症狀,背後總有一支具體的程序、一段排程或一支外掛在肇事。照著定位、分析、處理、預防這條線走一遍,下次再收到主機商的超標通知,你就不是慌張地猜哪裡出錯,而是打開 top 或 cPanel,幾步之內把兇手指出來。先從今天就把監控與告警設起來,別等到網站連不上才開始查。